packages feed

vision-0.0.5.0: src/Collection/List/View.hs

-- -*-haskell-*-
--  Vision (for the Voice): an XMMS2 client.
--
--  Author:  Oleg Belozeorov
--  Created: 10 Mar. 2010
--
--  Copyright (C) 2009-2011 Oleg Belozeorov
--  This program is free software; you can redistribute it and/or
--  modify it under the terms of the GNU General Public License as
--  published by the Free Software Foundation; either version 3 of
--  the License, or (at your option) any later version.
--
--  This program is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
--  General Public License for more details.
--

{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}

module Collection.List.View
  ( ListView (..)
  , mkListView
  ) where

import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TGVar

import Control.Applicative
import Control.Monad
import Control.Monad.Trans
import Control.Monad.EnvIO
import Control.Monad.W

import Data.Char (toLower)
import Data.List (isInfixOf)
import Data.IORef
import Data.Maybe

import Graphics.UI.Gtk

import XMMS2.Client

import Registry
import XMMS
import Utils
import Compound

import Collection.Common
import Collection.List.Model
import Collection.Actions
import Collection.Utils


data ListView
  = V { vView    :: TreeView
      , vSel     :: TreeSelection
      , vNextRef :: IORef VI
      , vStore   :: ListStore (Maybe (String, Coll))
      , vScroll  :: ScrolledWindow
      }

mkListView env = do
  Just me <- getEnv modelEnv
  store   <- runIn me $> store
  liftIO $ do
    let abRef = eABRef env
        ae    = eAE env
    view <- treeViewNewWithModel store
    treeViewSetHeadersVisible view False
    treeViewSetRulesHint view True

    sel <- treeViewGetSelection view
    treeSelectionSetMode sel SelectionMultiple
    setupTreeViewPopup view $ eLPopup env

    scroll <- scrolledWindowNew Nothing Nothing
    scrolledWindowSetShadowType scroll ShadowIn
    scrolledWindowSetPolicy scroll PolicyNever PolicyAutomatic
    containerAdd scroll view

    column <- treeViewColumnNew
    treeViewAppendColumn view column
    cell <- cellRendererTextNew
    treeViewColumnPackStart column cell True
    cellLayoutSetAttributes column cell store $ \n ->
      case n of
        Nothing ->
          [ cellText := "All Media", cellTextWeight := 800 ]
        Just cn ->
          [ cellText := fst cn, cellTextWeightSet := False ]

    treeViewSetEnableSearch view True
    treeViewSetSearchEqualFunc view . Just $ \str iter ->
      maybe False (isInfixOf (map toLower str) . map toLower . fst) <$>
      (listStoreGetValue store $ listStoreIterToIndex iter)

    nextRef <- newIORef None

    let v = V { vView    = view
              , vSel     = sel
              , vNextRef = nextRef
              , vStore   = store
              , vScroll  = scroll
              }

    let aef = do
          foc <- view `get` widgetHasFocus
          when foc $ do
            rows <- treeSelectionGetSelectedRows sel
            aEnableSel ae $ not $ null rows
            aEnableDel ae $ case rows of
              []      -> False
              [0] : _ -> False
              _       -> True
            aEnableRen ae $ case rows of
              [[0]] -> False
              [_]   -> True
              _     -> False
    setupViewFocus abRef view aef
      AB { aWithColl  = withBuiltColl v
         , aWithNames = \f -> withColls v (f . map fst . catMaybes)
         , aSelection = Just sel
         }
    sel `on` treeSelectionSelectionChanged $ aef

    xcW <- atomically $ newTGWatch connectedV
    tid <- forkIO $ forever $ do
      void $ atomically $ watch xcW
      postGUISync $ killNext v
    view `onDestroy` (killThread tid)

    widgetShowAll scroll
    return v

instance CollBuilder ListView where
  withBuiltColl lv f = withColls lv $ withColl f
  treeViewSel lv = (vView lv, vSel lv)

withColls lv f = do
  let store = vStore lv
      sel   = vSel lv
  rows <- treeSelectionGetSelectedRows sel
  unless (null rows) $ do
    colls <- mapM (listStoreGetValue store . head) rows
    f colls

withColl _ []            = return ()
withColl f (Nothing : _) = f =<< collUniverse
withColl f list = do
  uni <- collNew TypeUnion
  mapM_ (collAddOperand uni . snd) $ catMaybes list
  f uni

instance CompoundWidget ListView where
  type Outer ListView = ScrolledWindow
  outer = vScroll

instance FocusChild ListView where
  type Focus ListView = TreeView
  focus = vView

instance ViewItem ListView where
  nextVIRef = vNextRef