packages feed

vcsgui-0.2.1.0: src/VCSGui/Common/Log.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
-----------------------------------------------------------------------------
--
-- Module      :  VCSGui.Common.Log
-- Copyright   :  2011 Stephan Fortelny, Harald Jagenteufel
-- License     :  GPL
--
-- Maintainer  :  stephanfortelny at gmail.com, h.jagenteufel at gmail.com
-- Stability   :
-- Portability :
--
-- | Functions to show a log window. This mostly hides the window-building tasks from the specific VCS implementation.
--
-----------------------------------------------------------------------------
module VCSGui.Common.Log (
    showLogGUI
) where

import Control.Monad.Reader
import Data.Maybe

import VCSGui.Common.GtkHelper
import qualified VCSWrapper.Common as Common


import Data.Maybe (fromMaybe)
import Paths_vcsgui(getDataFileName)
import Data.Text (Text)
import qualified Data.Text as T (pack)
import Data.Monoid ((<>))
import qualified GI.Gtk.Objects.TreeView as Gtk
       (treeViewSetCursor, treeViewGetCursor, TreeView(..))
import qualified GI.Gtk.Objects.Action as Gtk (onActionActivate)
import qualified GI.Gtk.Objects.Widget as Gtk
       (setWidgetVisible, widgetShowAll)
import qualified GI.Gtk.Interfaces.TreeModel as Gtk
       (treeModelGetPath, treeModelGetIterFirst, treeModelGetIter)
import qualified Data.GI.Gtk.ModelView.SeqStore as Gtk
       (seqStoreIterToIndex, seqStoreGetValue, SeqStore(..))
import qualified Data.GI.Gtk.ComboBox as Gtk
       (comboBoxSetActive, comboBoxPrependText)
import qualified GI.Gtk.Objects.ComboBox as Gtk (onComboBoxChanged)
import GI.Gtk.Objects.TreeViewColumn (noTreeViewColumn)
import qualified GI.Gtk as Gtk (setCellRendererTextText)

getGladepath = getDataFileName "data/guiCommonLog.glade"

data LogConfig a = LogConfig {
    options :: [Text]
    ,treeViewSetter :: Gtk.TreeView -> TreeViewItem a
}


--------------------------------------------------
---- LOG VIEWER / CHECKOUT
--------------------------------------------------

data LogGUI = LogGUI {
    logWin :: WindowItem
    , logTreeView :: TreeViewItem Common.LogEntry
    , lblRevisionDetails :: LabelItem
    , actCheckout :: ActionItem
    , actLogCancel :: ActionItem
    , comboBranch :: ComboBoxItem
    , lblBranch :: LabelItem
}

-- | Show the history of a repository.
showLogGUI :: [Common.LogEntry]
            -- ^ logEntries to be displayed initially
            -> [Text]
            -- ^ options will be displayed in a menu as checkboxes (TODO this is currently not implemented)
            -> Maybe ((Text, [Text]), (Text -> Common.Ctx [Common.LogEntry]))
            -- ^ (list of branchnames to display, Function called when a different branch is selected)
            --
            -- The function will be called with the selected branchname to repopulate the displayed LogEntries.
            -- If 'Nothing', no branch selection will be displayed.
            -> (Common.LogEntry -> Maybe Text -> Common.Ctx ())
            -- ^ (selected line, name of the branch to checkout from)
            --
            -- This function is called on checkout action. The window will be closed afterwards.
            -> Bool -- ^ Add column to display branch name
            -> Common.Ctx ()
showLogGUI logEntries options Nothing doCheckoutFn displayBranchNames = guiWithoutBranches logEntries options doCheckoutFn displayBranchNames >> return ()
showLogGUI logEntries options (Just (branches, changeBranchFn)) doCheckoutFn displayBranchNames = do
        gui <- guiWithoutBranches logEntries options doCheckoutFn displayBranchNames
        guiAddBranches gui branches changeBranchFn
        return ()

guiWithoutBranches :: [Common.LogEntry]
                    -> [Text]
                    -> (Common.LogEntry
                        -> (Maybe Text)
                        -> Common.Ctx ())
                    -> Bool -- ^ Add column to display branch name
                    -> Common.Ctx LogGUI
guiWithoutBranches logEntries options doCheckoutFn displayBranchNames = do
        gui <- loadLogGui logEntries
        liftIO $ setupLogColumns gui displayBranchNames

        -- connect gui elements
        liftIO $ registerClose $ logWin gui
        liftIO $ registerCloseAction (actLogCancel gui) (logWin gui)

        config <- ask
        liftIO $ Gtk.onActionActivate (getItem (actCheckout gui)) $
            doCheckout' config (logTreeView gui) (comboBranch gui)
                >> (closeWin (logWin gui))

        -- show window
        liftIO $ Gtk.widgetShowAll $ getItem $ logWin gui
        return gui
    where
    doCheckout' :: Common.Config -> TreeViewItem Common.LogEntry -> ComboBoxItem -> IO ()
    doCheckout' cfg (_, (store, view), _) combo = do
        (mbPath, _) <- Gtk.treeViewGetCursor view
        case mbPath of
            Just path -> do
                (True, treeIter) <- Gtk.treeModelGetIter store path
                selectedLog <- Gtk.seqStoreGetValue store =<< Gtk.seqStoreIterToIndex treeIter
                selectedBranch <- get combo
                Common.runVcs cfg $ doCheckoutFn selectedLog selectedBranch
            Nothing -> return () -- TODO fix nothing selected bug here

    setupLogColumns :: LogGUI -> Bool -> IO ()
    setupLogColumns gui displayBranchNames = do
        let item = (logTreeView gui)
        addTextColumnToTreeView item "Subject" (\cell Common.LogEntry { Common.subject = t } -> Gtk.setCellRendererTextText cell t)
        addTextColumnToTreeView item "Author" (\cell Common.LogEntry { Common.author = t, Common.email = mail } -> Gtk.setCellRendererTextText cell $ t <> " <" <> mail <> ">")
        addTextColumnToTreeView item "Date" (\cell Common.LogEntry { Common.date = t } -> Gtk.setCellRendererTextText cell t)
        case displayBranchNames of
            True -> addTextColumnToTreeView item "Branch" (\cell Common.LogEntry { Common.mbBranch = t } -> Gtk.setCellRendererTextText cell $ fromMaybe "" t)
            False -> return()
        return ()

guiAddBranches :: LogGUI -> (Text, [Text]) -> (Text -> Common.Ctx [Common.LogEntry]) -> Common.Ctx ()
guiAddBranches gui (curBranch, otherBranches) changeBranchFn = do
        -- set branch selection visible
        liftIO $ Gtk.setWidgetVisible (getItem $ lblBranch gui) True
        liftIO $ Gtk.setWidgetVisible (getItem $ comboBranch gui) True

        -- fill with data®
        liftIO $ set (comboBranch gui) otherBranches
        liftIO $ Gtk.comboBoxPrependText (getItem $ comboBranch gui) curBranch
        liftIO $ Gtk.comboBoxSetActive (getItem $ comboBranch gui) 0

        -- register branch switch fn
        config <- ask
        liftIO $ Gtk.onComboBoxChanged (getItem $ comboBranch gui) $ changeBranchFn' config (fmap (fromMaybe "") $ get $ comboBranch gui)
        return ()
    where
    changeBranchFn' :: Common.Config -> IO Text -> IO ()
    changeBranchFn' cfg branchIO = do
        let (store, view) = getItem $ logTreeView gui
        branch <- branchIO
        newLogEntries <- Common.runVcs cfg $ changeBranchFn branch
        set (logTreeView gui) newLogEntries
        -- set cursor to first log entry (so checkoutbutton works)
        Gtk.treeModelGetIterFirst store >>= \case
            (True, firstRowIter) -> do
                firstRow <- Gtk.treeModelGetPath store firstRowIter
                Gtk.treeViewSetCursor view firstRow noTreeViewColumn False
            _ -> return ()


loadLogGui :: [Common.LogEntry] -> Common.Ctx LogGUI
loadLogGui logEntries = do
        liftIO $ do
            gladepath <- getGladepath
            builder <- openGladeFile gladepath
            win <- getWindowFromGlade builder "logWindow"
            revDetails <- getLabelFromGlade builder "lblRevisionDetails"
            actCheck <- getActionFromGlade builder "actCheckout"
            actCanc <- getActionFromGlade builder "actCancel"
            comboBranch <- getComboBoxFromGlade builder "comboBranch"
            lblBranch <- getLabelFromGlade builder "lblBranch"

            treeView <- getTreeViewFromGlade builder "historyTreeView" logEntries
            return $ LogGUI win treeView revDetails actCheck actCanc comboBranch lblBranch