module Manatee.Extension.Mplayer.PlaylistView where
import Control.Applicative
import Control.Concurrent.STM
import Control.Monad
import Data.Map (Map)
import Data.Text.Lazy (Text)
import Data.Typeable
import Graphics.UI.Gtk hiding (Statusbar, statusbarNew, get)
import Graphics.UI.Gtk.Gdk.SerializedEvent
import Manatee.Core.PageView
import Manatee.Core.Types
import Manatee.Extension.Mplayer.DBus
import Manatee.Extension.Mplayer.PlaylistBuffer
import Manatee.Toolkit.General.Basic
import Manatee.Toolkit.General.Functor
import Manatee.Toolkit.General.Maybe
import Manatee.Toolkit.General.STM
import Manatee.Toolkit.Gio.Gio
import Manatee.Toolkit.Gtk.Gtk
import Manatee.Toolkit.Gtk.ModelView
import Manatee.Toolkit.Gtk.ScrolledWindow
import System.GIO.File.ContentType
import System.Posix.Process
import System.Random
import qualified Data.Map as M
data PlaylistView =
PlaylistView {playlistViewPlugId :: TVar PagePlugId
,playlistViewScrolledWindow :: ScrolledWindow
,playlistViewBuffer :: PlaylistBuffer
,playlistViewTreeView :: TreeView
,playlistViewListStore :: ListStore MultimediaInfo
,playlistViewSortModel :: TypedTreeModelSort MultimediaInfo
,playlistViewCurrentPlayPath :: TVar TreePath
,playlistViewPlayMode :: TVar PlayMode}
deriving Typeable
instance PageBuffer PlaylistBuffer where
pageBufferGetName = readTVarIO . playlistBufferName
pageBufferSetName a = writeTVarIO (playlistBufferName a)
pageBufferClient = playlistBufferClient
pageBufferCreateView a pId = PageViewWrap <$> playlistViewNew a pId
pageBufferMode = playlistBufferMode
instance PageView PlaylistView where
pageViewBuffer = PageBufferWrap . playlistViewBuffer
pageViewPlugId = playlistViewPlugId
pageViewFocus = treeViewFocus . playlistViewTreeView
pageViewScrolledWindow = playlistViewScrolledWindow
pageViewHandleKeyAction = playlistViewHandleKeyAction
pageViewScrollToTop = playlistViewScrollToTop
pageViewScrollToBottom = playlistViewScrollToBottom
pageViewScrollVerticalPage = playlistViewScrollVerticalPage
pageViewScrollVerticalStep = playlistViewScrollVerticalStep
data PlayMode = SingleMode
| ListMode
| RandomMode
deriving (Show, Eq, Ord)
playlistViewNew :: PlaylistBuffer -> PagePlugId -> IO PlaylistView
playlistViewNew buffer plugId = do
pId <- newTVarIO plugId
scrolledWindow <- scrolledWindowNew_
treeView <- treeViewNew
treeViewSetEnableTreeLines treeView True
scrolledWindow `containerAdd` treeView
listStore <- listStoreNew []
sortModel <- treeModelSortNewWithModel listStore
path <- newTVarIO [0]
playMode <- newTVarIO ListMode
let playlistView = PlaylistView pId scrolledWindow buffer treeView listStore sortModel path playMode
playlistViewBuildMatchRule playlistView
playlistViewDraw playlistView
return playlistView
playlistViewBuildMatchRule :: PlaylistView -> IO ()
playlistViewBuildMatchRule view =
mkMplayerClientMatchRule
(pageViewClient view)
(PlayFinished,
\ _ -> do
mode <- readTVarIO (playlistViewPlayMode view)
case mode of
SingleMode -> playlistViewPlayCurrent view
ListMode -> playlistViewPlayNext view
RandomMode -> playlistViewPlayRandom view)
playlistViewSwitchPlayMode :: PlaylistView -> IO ()
playlistViewSwitchPlayMode view = do
mode <- readTVarIO (playlistViewPlayMode view)
let newMode = case mode of
SingleMode -> ListMode
ListMode -> RandomMode
RandomMode -> SingleMode
writeTVarIO (playlistViewPlayMode view) newMode
pageViewUpdateInfoStatus view "PlayMode" (" PlayMode (" ++ show newMode ++ ")")
playlistViewPlayCurrent :: PlaylistView -> IO ()
playlistViewPlayCurrent view = do
currentPath <- readTVarIO $ playlistViewCurrentPlayPath view
playlistViewPlayInternal view currentPath
playlistViewDraw :: PlaylistView -> IO ()
playlistViewDraw view = do
let buffer = playlistViewBuffer view
treeView = playlistViewTreeView view
store = playlistViewListStore view
model = playlistViewSortModel view
infos <- readTVarIO $ playlistBufferInfos buffer
listStoreClear store
forM_ infos (listStoreAppend store)
treeViewSetModel treeView model
treeViewRemoveColumns treeView
playlistViewAddIconColumn treeView store
forM_ (playlistBufferOptions buffer) (playlistViewAddColumn treeView store model)
sortStatus <- readTVarIO $ playlistBufferSortStatus buffer
playlistViewSortInternal view sortStatus
return ()
playlistViewSortInternal :: PlaylistView -> (MultimediaOption, SortType) -> IO ()
playlistViewSortInternal view (option, sortType) = do
let options = playlistBufferOptions $ playlistViewBuffer view
lookup option options ?>= \x ->
treeSortableSetSortColumnId (playlistViewSortModel view) x sortType
playlistViewAddIconColumn :: (TreeViewClass self
,TreeModelClass (model row)
,TypedTreeModelClass model)
=> self
-> model row
-> IO ()
playlistViewAddIconColumn treeView store = do
pixbuf <- getIconPixbuf $ contentTypeGetIcon "audio/mp3"
tvc <- treeViewColumnNew
set tvc [treeViewColumnTitle := ""]
treeViewAppendColumn treeView tvc
icon <- cellRendererPixbufNew
treeViewColumnPackStart tvc icon True
cellLayoutSetAttributes tvc icon store $ \_ -> [cellPixbuf := pixbuf]
playlistViewAddColumn :: (MultimediaInfoClass t
,TreeViewClass self1
,TreeModelClass self
,TreeModelSortClass self
,TypedTreeModelClass model
,TreeSortableClass self)
=> self1
-> model MultimediaInfo
-> self
-> (t, SortColumnId)
-> IO ()
playlistViewAddColumn treeView model sortModel option@(info,sortId) = do
playlistViewSetSortFunc model sortModel option
let name = getColumnTitle info
maxWidth = getColumnMaxWidth info
tvc <- treeViewAddColumnWithTitle treeView name sortId
maxWidth ?>= \width -> treeViewColumnSetMaxWidth tvc width
cell <- cellRendererTextNew
treeViewColumnPackStart tvc cell True
playlistViewSetCellText tvc cell model sortModel info
playlistViewSetSortFunc :: (TreeSortableClass self,
TypedTreeModelClass model,
MultimediaInfoClass a) =>
model MultimediaInfo
-> self
-> (a, SortColumnId)
-> IO ()
playlistViewSetSortFunc model sortModel (info, sortId) =
treeSortableSetSortFunc sortModel sortId $ \iter1 iter2 -> do
row1 <- treeModelGetRow model iter1
row2 <- treeModelGetRow model iter2
compareRow info row1 row2
playlistViewSetCellText :: (CellLayoutClass self,
CellRendererTextClass cell,
TreeModelClass model,
TreeModelSortClass model,
TypedTreeModelClass model1,
MultimediaInfoClass a)
=> self
-> cell
-> model1 MultimediaInfo
-> model
-> a
-> IO ()
playlistViewSetCellText tvc cell model sortModel info =
cellLayoutSetAttributeFunc tvc cell sortModel $ \iter -> do
row <- treeModelSortGetRow model sortModel iter
set cell [cellText := getCellText info row
,cellXAlign := getCellXAlign info]
playlistViewNextNode :: PlaylistView -> IO ()
playlistViewNextNode = treeViewFocusNextToplevelNode . playlistViewTreeView
playlistViewPrevNode :: PlaylistView -> IO ()
playlistViewPrevNode = treeViewFocusPrevToplevelNode . playlistViewTreeView
playlistViewKeymap :: Map Text (PlaylistView -> IO ())
playlistViewKeymap =
M.fromList
[("j", playlistViewNextNode)
,("k", playlistViewPrevNode)
,("Down", playlistViewNextNode)
,("Up", playlistViewPrevNode)
,("J", playlistViewScrollToBottom)
,("K", playlistViewScrollToTop)
,(" ", playlistViewScrollVerticalPage True)
,("b", playlistViewScrollVerticalPage False)
,("PageDown", playlistViewScrollVerticalPage True)
,("PageUp", playlistViewScrollVerticalPage False)
,("m", playlistViewPlay)
,("Return", playlistViewPlay)
,("M", playlistViewPause)
,("z", playlistViewStop)
,("h", playlistViewBackward)
,("l", playlistViewForward)
,("Right", playlistViewBackward)
,("Left", playlistViewForward)
,(",", playlistViewVolumeDec)
,(".", playlistViewVolumeInc)
,("-", playlistViewVolumeDec)
,("=", playlistViewVolumeInc)
,("n", playlistViewPlayNext)
,("p", playlistViewPlayPrev)
,("N", playlistViewPlayRandom)
,("P", playlistViewSwitchPlayMode)
,("1", playlistViewSortByTitle)
,("2", playlistViewSortByAlbum)
,("3", playlistViewSortByArtist)
,("4", playlistViewSortByYear)
,("5", playlistViewSortByTrack)
,("6", playlistViewSortByBitRate)
,("7", playlistViewSortByDuration)
]
playlistViewSortByTitle :: PlaylistView -> IO ()
playlistViewSortByTitle view = playlistViewSort view MOTitle
playlistViewSortByAlbum :: PlaylistView -> IO ()
playlistViewSortByAlbum view = playlistViewSort view MOAlbum
playlistViewSortByArtist :: PlaylistView -> IO ()
playlistViewSortByArtist view = playlistViewSort view MOArtist
playlistViewSortByYear :: PlaylistView -> IO ()
playlistViewSortByYear view = playlistViewSort view MOYear
playlistViewSortByTrack :: PlaylistView -> IO ()
playlistViewSortByTrack view = playlistViewSort view MOTrack
playlistViewSortByBitRate :: PlaylistView -> IO ()
playlistViewSortByBitRate view = playlistViewSort view MOBitRate
playlistViewSortByDuration :: PlaylistView -> IO ()
playlistViewSortByDuration view = playlistViewSort view MODuration
playlistViewSort :: PlaylistView -> MultimediaOption -> IO ()
playlistViewSort view option = do
let model = playlistViewSortModel view
buffer = playlistViewBuffer view
options = playlistBufferOptions buffer
(curSortType, _, curSortColumnId) <- treeSortableGetSortColumnId model
lookup option options ?>= \id -> do
treeSortableSetSortColumnId model id $
if id == curSortColumnId
then
case curSortType of
SortAscending -> SortDescending
SortDescending -> SortAscending
else SortAscending
(newSortType, _, _) <- treeSortableGetSortColumnId model
writeTVarIO (playlistBufferSortStatus $ playlistViewBuffer view) (option, newSortType)
treeViewFocus (playlistViewTreeView view)
playlistViewPlay :: PlaylistView -> IO ()
playlistViewPlay view = do
let treeView = playlistViewTreeView view
treeViewGetSelectedPath treeView
>?>= \ path -> do
currentPath <- treeModelSortConvertPathToChildPath (playlistViewSortModel view) path
playlistViewPlayInternal view currentPath
playlistViewPlayRandom :: PlaylistView -> IO ()
playlistViewPlayRandom view = do
size <- treeViewGetToplevelNodeCount (playlistViewTreeView view)
randomIndex <- randomRIO (0, size 1)
playlistViewPlayInternal view [randomIndex]
playlistViewPlayNext :: PlaylistView -> IO ()
playlistViewPlayNext view = do
currentPath <- readTVarIO $ playlistViewCurrentPlayPath view
nextSortPath <- treeViewNextSortPath (playlistViewTreeView view) (playlistViewSortModel view) currentPath
playlistViewPlayInternal view nextSortPath
playlistViewPlayPrev :: PlaylistView -> IO ()
playlistViewPlayPrev view = do
currentPath <- readTVarIO $ playlistViewCurrentPlayPath view
prevSortPath <- treeViewPrevSortPath (playlistViewTreeView view) (playlistViewSortModel view) currentPath
playlistViewPlayInternal view prevSortPath
playlistViewPlayInternal :: PlaylistView -> TreePath -> IO ()
playlistViewPlayInternal view path = do
filePath <- liftM miFilePath $ listStoreGetValue (playlistViewListStore view) (head path)
let displayPath = filepathGetDisplayName filePath
writeTVarIO (playlistViewCurrentPlayPath view) path
mode <- readTVarIO (playlistViewPlayMode view)
pageViewUpdateInfoStatus view "PlayMode" (" PlayMode (" ++ show mode ++ ")")
pageViewUpdateInfoStatus view "Playing" (" Playing : " ++ displayPath)
processId <- getProcessID
mkMplayerDaemonSignal (pageViewClient view) Play (PlayArgs filePath processId)
playlistViewStop :: PlaylistView -> IO ()
playlistViewStop view =
mkMplayerDaemonSignal (pageViewClient view) Stop StopArgs
playlistViewPause :: PlaylistView -> IO ()
playlistViewPause view =
mkMplayerDaemonSignal (pageViewClient view) Pause PauseArgs
playlistViewForward :: PlaylistView -> IO ()
playlistViewForward view =
mkMplayerDaemonSignal (pageViewClient view) Forward (ForwardArgs 10)
playlistViewBackward :: PlaylistView -> IO ()
playlistViewBackward view =
mkMplayerDaemonSignal (pageViewClient view) Backward (BackwardArgs 10)
playlistViewVolumeInc :: PlaylistView -> IO ()
playlistViewVolumeInc view =
mkMplayerDaemonSignal (pageViewClient view) VolumeInc (VolumeIncArgs 10)
playlistViewVolumeDec :: PlaylistView -> IO ()
playlistViewVolumeDec view =
mkMplayerDaemonSignal (pageViewClient view) VolumeDec (VolumeDecArgs 10)
playlistViewScrollToTop :: PlaylistView -> IO ()
playlistViewScrollToTop =
treeViewFocusFirstToplevelNode . playlistViewTreeView
playlistViewScrollToBottom :: PlaylistView -> IO ()
playlistViewScrollToBottom =
treeViewFocusLastToplevelNode . playlistViewTreeView
playlistViewScrollVerticalPage :: Bool -> PlaylistView -> IO ()
playlistViewScrollVerticalPage isDown a = do
let sw = playlistViewScrolledWindow a
tv = playlistViewTreeView a
pageInc <- (<=<) adjustmentGetPageIncrement scrolledWindowGetVAdjustment sw
treeViewScrollVertical tv sw (if isDown then pageInc else ( pageInc))
playlistViewScrollVerticalStep :: Bool -> PlaylistView -> IO ()
playlistViewScrollVerticalStep isDown a = do
let sw = playlistViewScrolledWindow a
tv = playlistViewTreeView a
stepInc <- (<<<=) i2d treeViewGetSelectedCellHeight tv
treeViewScrollVertical tv sw (if isDown then stepInc else ( stepInc))
playlistViewHandleKeyAction :: PlaylistView -> Text -> SerializedEvent -> IO ()
playlistViewHandleKeyAction view keystoke sEvent =
case M.lookup keystoke playlistViewKeymap of
Just action -> action view
Nothing -> widgetPropagateEvent (playlistViewTreeView view) sEvent