packages feed

apelsin-1.2: src/FilterBar.hs

module FilterBar (newFilterBar, smartFilter) where

import Graphics.UI.Gtk
import Data.IORef
import qualified Data.ByteString.Char8 as B
import Data.ByteString.Char8 (ByteString)
import Data.Char hiding (Control)
import Control.Applicative
import Control.Monad.IO.Class
import Network.Tremulous.ByteStringUtils as B

import GtkExts
import Constants


newFilterBar :: (TreeModelClass self, TreeModelFilterClass self) => Window -> self -> Label -> String
	-> IO (HBox, IORef [Expr])
newFilterBar win filtered stat initial  = do
	current <- newIORef []

	-- Filterbar
	ent <- entryNew
	set ent [ entryText := initial ]
	entrySetIconFromStock ent EntryIconSecondary stockClear

	lbl <- labelNew (Just "Filter:")
	set lbl [ widgetTooltipText := Just "Ctrl+L or Ctrl+F" ]

	findbar <- hBoxNew False 0
	boxPackStart findbar lbl PackNatural spacingHalf
	boxPackStart findbar ent PackGrow spacingHalf

	let f = do
		str <- entryGetText ent
		writeIORef current (stringToExpr str)
		treeModelFilterRefilter filtered
		labelSetText stat . show =<< treeModelIterNChildren filtered Nothing
	f
	on ent editableChanged f

	on ent entryIconPress $
		const $ liftIO $ editableDeleteText ent 0 (-1)

	on win keyPressEvent $ do
		s	<- eventModifier
		k	<- fromIntegral . keyvalToLower <$> eventKeyVal
		b 	<- liftIO $ widgetGetMapped ent
		if b && s == [Control] && (k == ord 'f' || k == ord 'l')
			then liftIO (widgetGrabFocus ent) >> return True
			else return False

	-- Focus on start
	on ent showSignal $ widgetGrabFocus ent

	return (findbar, current)


data Expr = Is !ByteString | Not !ByteString

mkExpr :: ByteString -> Expr
mkExpr ss = case B.uncons ss of
	Just ('-', xs)	| B.length xs > 0	-> Not (B.tail ss)
			| otherwise		-> Is xs
	_					-> Is ss

matchExpr :: Expr -> [ByteString] -> Bool
matchExpr (Is xs)  = any (xs `B.isInfixOf`)
matchExpr (Not xs) = all (not . (xs `B.isInfixOf`))

stringToExpr :: String -> [Expr]
stringToExpr = map mkExpr . B.splitfilter ' ' . B.pack . map toLower

smartFilter :: [Expr]-> [ByteString] -> Bool
smartFilter [] 	_	= True
smartFilter expr xs	= all (`matchExpr` xs) expr