{-# LANGUAGE DeriveDataTypeable #-} module Main where import System.Environment (getArgs) import Data.Text (Text) import qualified Data.Text as T import Data.Typeable (Typeable) import qualified Database.SQLite.Simple as S import qualified Database.SQLite.Simple.FromField as S import qualified Database.SQLite.Simple.ToField as S import Graphics.QML import Paths_hsqml_demo_notes newtype Note = Note {noteId :: Int} deriving (Eq, Ord, Typeable) createTable :: S.Connection -> IO () createTable conn = S.execute_ conn . S.Query . T.pack $ "CREATE TABLE IF NOT EXISTS notes (" ++ "id INTEGER PRIMARY KEY AUTOINCREMENT, " ++ "x INTEGER, y INTEGER, reverse BOOLEAN, front TEXT, back TEXT)" selectNotes :: S.Connection -> a -> (a -> Note -> IO a) -> IO a selectNotes conn zero func = let query = S.Query $ T.pack "SELECT id FROM notes ORDER BY id DESC" in S.fold_ conn query zero (\acc (S.Only i) -> func acc $ Note i) insertNote :: S.Connection -> Int -> Int -> Text -> IO () insertNote conn x y front = S.execute conn (S.Query $ T.pack "INSERT INTO notes (x,y,reverse,front,back) VALUES (?, ?, 0, ?, '')") (x, y, front) deleteNote :: S.Connection -> Note -> IO () deleteNote conn = let query = S.Query $ T.pack "DELETE FROM notes WHERE id = ?" in S.execute conn query . S.Only . noteId readNoteAttrib :: (S.FromField a) => S.Connection -> String -> ObjRef Note -> IO a readNoteAttrib conn attrib note = do let query = S.Query . T.pack $ "SELECT " ++ attrib ++ " FROM notes WHERE id = ?" [S.Only value] <- S.query conn query (S.Only . noteId $ fromObjRef note) return value writeNoteAttrib :: (S.ToField a) => S.Connection -> String -> SignalKey (IO ()) -> ObjRef Note -> a -> IO () writeNoteAttrib conn attrib changeKey note value = do let query = S.Query . T.pack $ "UPDATE notes SET " ++ attrib ++ " = ? WHERE id = ?" S.execute conn query (value, noteId $ fromObjRef note) fireSignal changeKey note createContext :: S.Connection -> IO (ObjRef ()) createContext conn = do changeKey <- newSignalKey noteClass <- newClass [ defPropertySigRW "x" changeKey (readNoteAttrib conn "x" :: ObjRef Note -> IO Int) (writeNoteAttrib conn "x" changeKey), defPropertySigRW "y" changeKey (readNoteAttrib conn "y" :: ObjRef Note -> IO Int) (writeNoteAttrib conn "y" changeKey), defPropertySigRW "reverse" changeKey (readNoteAttrib conn "reverse" :: ObjRef Note -> IO Bool) (writeNoteAttrib conn "reverse" changeKey), defPropertySigRW "front" changeKey (readNoteAttrib conn "front" :: ObjRef Note -> IO Text) (writeNoteAttrib conn "front" changeKey), defPropertySigRW "back" changeKey (readNoteAttrib conn "back" :: ObjRef Note -> IO Text) (writeNoteAttrib conn "back" changeKey)] notePool <- newFactoryPool (newObject noteClass) rootClass <- newClass [ defPropertySigRO' "notes" changeKey (\_ -> selectNotes conn [] (\objs note -> do object <- getPoolObject notePool note return $ object:objs)), defMethod' "insertNote" (\this x y front -> do insertNote conn x y front fireSignal changeKey this), defMethod' "deleteNote" (\this note -> do deleteNote conn $ fromObjRef note fireSignal changeKey this)] newObject rootClass () main :: IO () main = S.withConnection "notes.db" $ \conn -> do createTable conn ctx <- createContext conn args <- getArgs path <- case args of ("local":p:_) -> return $ p ++ ".qml" (p:_) -> getDataFileName $ p ++ ".qml" _ -> getDataFileName "notes.qml" runEngineLoop defaultEngineConfig { initialDocument = fileDocument path, contextObject = Just $ anyObjRef ctx}