vision-0.0.3.0: src/Properties/View.hs
-- -*-haskell-*-
-- Vision (for the Voice): an XMMS2 client.
--
-- Author: Oleg Belozeorov
-- Created: 22 Mar. 2010
--
-- Copyright (C) 2009-2010 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.
--
{-# LANGUAGE TupleSections #-}
module Properties.View
( PropertyView
, makePropertyView
, propertyViewStore
, propertyViewRight
) where
import Control.Applicative
import Control.Monad
import Control.Monad.Trans
import Data.IORef
import Data.Maybe
import Data.Set (Set)
import qualified Data.Set as Set
import Graphics.UI.Gtk
import Atoms
import Compound
import Editor
import DnD
import Properties.Property
import Properties.Model
data PropertyView a
= PropertyView
{ vPaned :: HPaned
, vFilter :: TreeModelFilter
, vLeft :: TreeView
, propertyViewStore :: ListStore (Property, a)
, propertyViewRight :: TreeView
, vModified :: IORef Bool
, vSelected :: IORef (Set String)
}
instance CompoundWidget (PropertyView a) where
type Outer (PropertyView a) = HPaned
outer = vPaned
instance EditorWidget (PropertyView a) where
type Data (PropertyView a) = [(Property, a)]
getData = propertyViewGetData
setData = propertyViewSetData
clearData = propertyViewClearData
setupView = propertyViewSetupView
focusView = propertyViewFocusView
getState = propertyViewGetState
resetModified = propertyViewResetModified
propertyViewGetData =
listStoreToList . propertyViewStore
propertyViewSetData v d = do
listStoreClear $ propertyViewStore v
mapM_ (listStoreAppend $ propertyViewStore v) d
writeIORef (vSelected v) $ Set.fromList $ map (propName . fst) d
treeModelFilterRefilter (vFilter v)
propertyViewClearData =
flip propertyViewSetData []
propertyViewSetupView pm =
treeViewSetCursor (vLeft pm) [0] Nothing
propertyViewFocusView =
widgetGrabFocus . vLeft
propertyViewGetState =
liftM (True, ) . readIORef . vModified
propertyViewResetModified =
flip writeIORef False . vModified
makePropertyView make _ notify = do
selected <- newIORef Set.empty
modified <- newIORef False
let onChanged = do
writeIORef modified True
notify
paned <- hPanedNew
containerSetBorderWidth paned 7
scroll <- scrolledWindowNew Nothing Nothing
scrolledWindowSetPolicy scroll PolicyAutomatic PolicyAutomatic
scrolledWindowSetShadowType scroll ShadowIn
panedPack1 paned scroll True False
filter <- treeModelFilterNew propertyStore []
treeModelFilterSetVisibleFunc filter $ Just $ \iter -> do
[n] <- treeModelGetPath propertyStore iter
prop <- listStoreGetValue propertyStore n
seld <- readIORef selected
return $ Set.notMember (propName prop) seld
left <- treeViewNewWithModel filter
treeViewSetHeadersVisible left False
sel <- treeViewGetSelection left
treeSelectionSetMode sel SelectionMultiple
column <- treeViewColumnNew
treeViewAppendColumn left column
cell <- cellRendererTextNew
treeViewColumnPackStart column cell True
cellLayoutSetAttributes column cell propertyStore $ \prop ->
[ cellText := propName prop ]
containerAdd scroll left
scroll <- scrolledWindowNew Nothing Nothing
scrolledWindowSetPolicy scroll PolicyAutomatic PolicyAutomatic
scrolledWindowSetShadowType scroll ShadowIn
panedPack2 paned scroll True False
store <- listStoreNew []
store `on` rowChanged $ const $ const onChanged
store `on` rowInserted $ const $ const onChanged
store `on` rowDeleted $ const onChanged
right <- treeViewNewWithModel store
treeViewSetHeadersVisible right False
treeViewSetReorderable right True
sel <- treeViewGetSelection right
treeSelectionSetMode sel SelectionMultiple
column <- treeViewColumnNew
treeViewAppendColumn right column
cell <- cellRendererTextNew
treeViewColumnPackStart column cell True
cellLayoutSetAttributes column cell store $ \(prop, _) ->
[ cellText := propName prop ]
containerAdd scroll right
let updFilter func props = do
modifyIORef selected $ func (Set.fromList $ map propName props)
treeModelFilterRefilter filter
addProps = do
sel <- treeViewGetSelection left
rows <- treeSelectionGetSelectedRows sel
rows <- mapM (treeModelFilterConvertPathToChildPath filter) rows
props <- mapM (listStoreGetValue propertyStore . head) rows
mapM (listStoreAppend store . make) props
updFilter Set.union props
left `onRowActivated` \_ _ -> addProps
left `on` keyPressEvent $ tryEvent $ do
[] <- eventModifier
"Return" <- eventKeyName
liftIO addProps
setupLeftDnD filter left
right `on` keyPressEvent $ tryEvent $ do
[] <- eventModifier
"Delete" <- eventKeyName
liftIO $ do
sel <- treeViewGetSelection right
rows <- treeSelectionGetSelectedRows sel
props <- mapM (listStoreGetValue store . head) rows
mapM_ (listStoreRemove store . head) $ reverse rows
updFilter (flip Set.difference) $ map fst props
setupRightDnD store right make updFilter
return PropertyView { vPaned = paned
, vFilter = toTreeModelFilter filter
, vLeft = left
, propertyViewStore = store
, propertyViewRight = right
, vModified = modified
, vSelected = selected
}
setupLeftDnD filter left = do
targetList <- targetListNew
targetListAdd targetList propertyNameListTarget [TargetSameApp] 0
dragSourceSet left [Button1] [ActionCopy]
dragSourceSetTargetList left targetList
sel <- treeViewGetSelection left
left `on` dragDataGet $ \_ _ _ -> do
names <- liftIO $ do
rows <- treeSelectionGetSelectedRows sel
rows <- mapM (treeModelFilterConvertPathToChildPath filter) rows
mapM (liftM propName . listStoreGetValue propertyStore . head) rows
selectionDataSetStringList names
setupDragDest left
[DestDefaultMotion, DestDefaultHighlight]
[ActionMove]
[ indexListTarget :>: \_ _ -> do
liftIO $ signalStopEmission left "drag_data_received"
return (True, True)
]
return ()
setupRightDnD store view make updFilter = do
targetList <- targetListNew
targetListAdd targetList indexListTarget [TargetSameApp] 0
dragSourceSet view [Button1] [ActionDefault, ActionMove]
dragSourceSetTargetList view targetList
sel <- treeViewGetSelection view
view `on` dragDataGet $ \_ _ _ -> do
rows <- liftIO $ treeSelectionGetSelectedRows sel
selectionDataSet selectionTypeInteger $ map head rows
return ()
setupDragDest view
[DestDefaultMotion, DestDefaultHighlight]
[ActionCopy, ActionDefault]
[ indexListTarget :>: reorderRows store view
(mapM_ $ \(f, t) -> do
v <- listStoreGetValue store f
listStoreRemove store f
listStoreInsert store t v)
, propertyNameListTarget :>: \_ (_, y) -> do
names <- selectionDataGetStringList
liftIO $ do
props <- map make . catMaybes <$> mapM property names
base <- getTargetRow store view y False
zipWithM_ (listStoreInsert store) [base .. ] props
updFilter Set.union $ map fst props
return (True, False)
]
view `on` dragDataDelete $ \_ -> do
rows <- treeSelectionGetSelectedRows sel
props <- mapM (listStoreGetValue store . head) rows
mapM_ (listStoreRemove store . head) $ reverse rows
updFilter (flip Set.difference) $ map fst props