From 4fac84dde4b5d3a6706d0cc096c83e127a33c602 Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Wed, 1 Jun 2016 19:32:51 +0200 Subject: [PATCH] Initial commit --- HSFM-FileSystem-FileType.html | 34 ++ HSFM-FileSystem-UtilTypes.html | 18 + HSFM-GUI-Glib-GlibString.html | 4 + HSFM-GUI-Gtk-Callbacks-Utils.html | 5 + HSFM-GUI-Gtk-Callbacks.html | 5 + HSFM-GUI-Gtk-Data.html | 8 + HSFM-GUI-Gtk-Dialogs.html | 7 + HSFM-GUI-Gtk-Errors.html | 4 + HSFM-GUI-Gtk-Icons.html | 5 + HSFM-GUI-Gtk-MyGUI.html | 4 + HSFM-GUI-Gtk-MyView.html | 14 + HSFM-GUI-Gtk-Utils.html | 11 + HSFM-Utils-IO.html | 4 + HSFM-Utils-MyPrelude.html | 6 + Main.html | 4 + Paths_hsfm.html | 4 + doc-index-95.html | 4 + doc-index-A.html | 4 + doc-index-All.html | 4 + doc-index-B.html | 4 + doc-index-C.html | 4 + doc-index-D.html | 4 + doc-index-E.html | 4 + doc-index-F.html | 4 + doc-index-G.html | 4 + doc-index-H.html | 4 + doc-index-I.html | 4 + doc-index-L.html | 4 + doc-index-M.html | 4 + doc-index-N.html | 4 + doc-index-O.html | 4 + doc-index-P.html | 4 + doc-index-R.html | 4 + doc-index-S.html | 4 + doc-index-T.html | 4 + doc-index-U.html | 4 + doc-index-V.html | 4 + doc-index-W.html | 4 + doc-index.html | 4 + frames.html | 30 ++ haddock-util.js | 344 ++++++++++++++ hsfm.haddock | Bin 0 -> 46155 bytes hslogo-16.png | Bin 0 -> 1684 bytes index-frames.html | 4 + index.html | 4 + mini_HSFM-FileSystem-FileType.html | 4 + mini_HSFM-FileSystem-UtilTypes.html | 4 + mini_HSFM-GUI-Glib-GlibString.html | 4 + mini_HSFM-GUI-Gtk-Callbacks-Utils.html | 4 + mini_HSFM-GUI-Gtk-Callbacks.html | 4 + mini_HSFM-GUI-Gtk-Data.html | 4 + mini_HSFM-GUI-Gtk-Dialogs.html | 4 + mini_HSFM-GUI-Gtk-Errors.html | 4 + mini_HSFM-GUI-Gtk-Icons.html | 4 + mini_HSFM-GUI-Gtk-MyGUI.html | 4 + mini_HSFM-GUI-Gtk-MyView.html | 4 + mini_HSFM-GUI-Gtk-Utils.html | 4 + mini_HSFM-Utils-IO.html | 4 + mini_HSFM-Utils-MyPrelude.html | 4 + mini_Main.html | 4 + mini_Paths_hsfm.html | 4 + minus.gif | Bin 0 -> 56 bytes ocean.css | 610 +++++++++++++++++++++++++ plus.gif | Bin 0 -> 59 bytes src/HSFM-GUI-Glib-GlibString.html | 91 ++++ src/HSFM-GUI-Gtk-Callbacks-Utils.html | 121 +++++ src/HSFM-GUI-Gtk-Callbacks.html | 554 ++++++++++++++++++++++ src/HSFM-GUI-Gtk-Data.html | 161 +++++++ src/HSFM-GUI-Gtk-Dialogs.html | 313 +++++++++++++ src/HSFM-GUI-Gtk-Errors.html | 45 ++ src/HSFM-GUI-Gtk-Icons.html | 82 ++++ src/HSFM-GUI-Gtk-MyGUI.html | 108 +++++ src/HSFM-GUI-Gtk-MyView.html | 467 +++++++++++++++++++ src/HSFM-GUI-Gtk-Utils.html | 177 +++++++ src/HSFM-Utils-MyPrelude.html | 47 ++ src/Main.html | 71 +++ src/hscolour.css | 5 + synopsis.png | Bin 0 -> 11327 bytes 78 files changed, 3527 insertions(+) create mode 100644 HSFM-FileSystem-FileType.html create mode 100644 HSFM-FileSystem-UtilTypes.html create mode 100644 HSFM-GUI-Glib-GlibString.html create mode 100644 HSFM-GUI-Gtk-Callbacks-Utils.html create mode 100644 HSFM-GUI-Gtk-Callbacks.html create mode 100644 HSFM-GUI-Gtk-Data.html create mode 100644 HSFM-GUI-Gtk-Dialogs.html create mode 100644 HSFM-GUI-Gtk-Errors.html create mode 100644 HSFM-GUI-Gtk-Icons.html create mode 100644 HSFM-GUI-Gtk-MyGUI.html create mode 100644 HSFM-GUI-Gtk-MyView.html create mode 100644 HSFM-GUI-Gtk-Utils.html create mode 100644 HSFM-Utils-IO.html create mode 100644 HSFM-Utils-MyPrelude.html create mode 100644 Main.html create mode 100644 Paths_hsfm.html create mode 100644 doc-index-95.html create mode 100644 doc-index-A.html create mode 100644 doc-index-All.html create mode 100644 doc-index-B.html create mode 100644 doc-index-C.html create mode 100644 doc-index-D.html create mode 100644 doc-index-E.html create mode 100644 doc-index-F.html create mode 100644 doc-index-G.html create mode 100644 doc-index-H.html create mode 100644 doc-index-I.html create mode 100644 doc-index-L.html create mode 100644 doc-index-M.html create mode 100644 doc-index-N.html create mode 100644 doc-index-O.html create mode 100644 doc-index-P.html create mode 100644 doc-index-R.html create mode 100644 doc-index-S.html create mode 100644 doc-index-T.html create mode 100644 doc-index-U.html create mode 100644 doc-index-V.html create mode 100644 doc-index-W.html create mode 100644 doc-index.html create mode 100644 frames.html create mode 100644 haddock-util.js create mode 100644 hsfm.haddock create mode 100644 hslogo-16.png create mode 100644 index-frames.html create mode 100644 index.html create mode 100644 mini_HSFM-FileSystem-FileType.html create mode 100644 mini_HSFM-FileSystem-UtilTypes.html create mode 100644 mini_HSFM-GUI-Glib-GlibString.html create mode 100644 mini_HSFM-GUI-Gtk-Callbacks-Utils.html create mode 100644 mini_HSFM-GUI-Gtk-Callbacks.html create mode 100644 mini_HSFM-GUI-Gtk-Data.html create mode 100644 mini_HSFM-GUI-Gtk-Dialogs.html create mode 100644 mini_HSFM-GUI-Gtk-Errors.html create mode 100644 mini_HSFM-GUI-Gtk-Icons.html create mode 100644 mini_HSFM-GUI-Gtk-MyGUI.html create mode 100644 mini_HSFM-GUI-Gtk-MyView.html create mode 100644 mini_HSFM-GUI-Gtk-Utils.html create mode 100644 mini_HSFM-Utils-IO.html create mode 100644 mini_HSFM-Utils-MyPrelude.html create mode 100644 mini_Main.html create mode 100644 mini_Paths_hsfm.html create mode 100644 minus.gif create mode 100644 ocean.css create mode 100644 plus.gif create mode 100644 src/HSFM-GUI-Glib-GlibString.html create mode 100644 src/HSFM-GUI-Gtk-Callbacks-Utils.html create mode 100644 src/HSFM-GUI-Gtk-Callbacks.html create mode 100644 src/HSFM-GUI-Gtk-Data.html create mode 100644 src/HSFM-GUI-Gtk-Dialogs.html create mode 100644 src/HSFM-GUI-Gtk-Errors.html create mode 100644 src/HSFM-GUI-Gtk-Icons.html create mode 100644 src/HSFM-GUI-Gtk-MyGUI.html create mode 100644 src/HSFM-GUI-Gtk-MyView.html create mode 100644 src/HSFM-GUI-Gtk-Utils.html create mode 100644 src/HSFM-Utils-MyPrelude.html create mode 100644 src/Main.html create mode 100644 src/hscolour.css create mode 100644 synopsis.png diff --git a/HSFM-FileSystem-FileType.html b/HSFM-FileSystem-FileType.html new file mode 100644 index 0000000..3e3598e --- /dev/null +++ b/HSFM-FileSystem-FileType.html @@ -0,0 +1,34 @@ +HSFM.FileSystem.FileType

hsfm-gtk

Safe HaskellNone
LanguageHaskell2010

HSFM.FileSystem.FileType

Description

This module provides a data type for representing directories/files + in a well-typed and convenient way. This is useful to gather and + save information about a file, so the information can be easily + processed in e.g. a GUI.

However, it's not meant to be used to interact with low-level + functions that copy files etc, since there's no guarantee that + the in-memory representation of the type still matches what is + happening on filesystem level.

If you interact with low-level libraries, you must not pattern + match on the `File a` type. Instead, you should only use the saved + path and make no assumptions about the file the path might or + might not point to.

Synopsis

Documentation

data File a Source #

The String in the path field is always a full path. + The free type variable is used in the File/Dir constructor and can hold + Handles, Strings representing a file's contents or anything else you can + think of. We catch any IO errors in the Failed constructor.

Constructors

Failed 

Fields

  • path :: !(Path Abs)
     
  • err :: IOError
     
Dir 

Fields

RegFile 

Fields

SymLink 

Fields

BlockDev 

Fields

CharDev 

Fields

NamedPipe 

Fields

Socket 

Fields

Instances

Eq a => Eq (File a) Source # 

Methods

(==) :: File a -> File a -> Bool

(/=) :: File a -> File a -> Bool

Ord (File FileInfo) Source #

First compare constructors: Failed < Dir < File... + Then compare name... + Then compare free variable parameter of File constructors

Show a => Show (File a) Source # 

Methods

showsPrec :: Int -> File a -> ShowS

show :: File a -> String

showList :: [File a] -> ShowS

data FileInfo Source #

Low-level file information.

Constructors

FileInfo 

Fields

Instances

Eq FileInfo Source # 

Methods

(==) :: FileInfo -> FileInfo -> Bool

(/=) :: FileInfo -> FileInfo -> Bool

Ord FileInfo Source # 

Methods

compare :: FileInfo -> FileInfo -> Ordering

(<) :: FileInfo -> FileInfo -> Bool

(<=) :: FileInfo -> FileInfo -> Bool

(>) :: FileInfo -> FileInfo -> Bool

(>=) :: FileInfo -> FileInfo -> Bool

max :: FileInfo -> FileInfo -> FileInfo

min :: FileInfo -> FileInfo -> FileInfo

Show FileInfo Source # 

Methods

showsPrec :: Int -> FileInfo -> ShowS

show :: FileInfo -> String

showList :: [FileInfo] -> ShowS

Ord (File FileInfo) Source #

First compare constructors: Failed < Dir < File... + Then compare name... + Then compare free variable parameter of File constructors

pattern FileLike :: File FileInfo -> File FileInfo Source #

Matches on any non-directory kind of files, excluding symlinks.

pattern DirList :: forall t. (Foldable t, Functor t) => t (File FileInfo) -> t (File FileInfo) Source #

Matches a list of directories or symlinks pointing to directories.

pattern FileLikeList :: forall t. (Foldable t, Functor t) => t (File FileInfo) -> t (File FileInfo) Source #

Matches a list of any non-directory kind of files or symlinks + pointing to such.

pattern FileLikeSym :: File FileInfo -> File FileInfo Source #

Matches on symlinks pointing to file-like files only.

pattern BrokenSymlink :: File FileInfo -> File FileInfo Source #

Matches on broken symbolic links.

pattern DirOrSym :: File FileInfo -> File FileInfo Source #

Matches on directories or symlinks pointing to directories. + If the symlink is pointing to a symlink pointing to a directory, then + it will return True, but also return the first element in the symlink- + chain, not the last.

pattern DirSym :: File FileInfo -> File FileInfo Source #

Matches on symlinks pointing to directories only.

pattern FileLikeOrSym :: File FileInfo -> File FileInfo Source #

Matches on any non-directory kind of files or symlinks pointing to + such. + If the symlink is pointing to a symlink pointing to such a file, then + it will return True, but also return the first element in the symlink- + chain, not the last.

readFile :: (Path Abs -> IO a) -> Path Abs -> IO (File a) Source #

Reads a file or directory Path into an AnchoredFile, filling the free + variables via the given function.

readDirectoryContents Source #

Arguments

:: (Path Abs -> IO a)

fills free a variable

-> Path Abs

path to read

-> IO [File a] 

Get the contents of a given directory and return them as a list + of AnchoredFile.

getContents :: (Path Abs -> IO a) -> File FileInfo -> IO [File a] Source #

A variant of readDirectoryContents where the second argument + is a File. If a non-directory is passed returns an empty list.

goUp :: File FileInfo -> IO (File FileInfo) Source #

Go up one directory in the filesystem hierarchy.

goUp' :: Path Abs -> IO (File FileInfo) Source #

Go up one directory in the filesystem hierarchy.

anyFailed :: [File a] -> Bool Source #

True if any Failed constructors in the tree.

successful :: [File a] -> Bool Source #

True if there are no Failed constructors in the tree.

failed :: File a -> Bool Source #

Returns true if argument is a Failed constructor.

failures :: [File a] -> [File a] Source #

Returns a list of Failed constructors only.

isFileC :: File a -> Bool Source #

isDirC :: File a -> Bool Source #

isSymC :: File a -> Bool Source #

isBlockC :: File a -> Bool Source #

isCharC :: File a -> Bool Source #

isNamedC :: File a -> Bool Source #

isSocketC :: File a -> Bool Source #

getFileInfo :: Path Abs -> IO FileInfo Source #

Gets all file information.

handleDT :: Path Abs -> IO (File a) -> IO (File a) Source #

isBrokenSymlink :: File FileInfo -> Bool Source #

Checks if a symlink is broken by examining the constructor of the + symlink destination.

When called on a non-symlink, returns False.

packModTime :: File FileInfo -> String Source #

Pack the modification time into a string.

packAccessTime :: File FileInfo -> String Source #

Pack the modification time into a string.

epochToString :: EpochTime -> String Source #

packPermissions :: File FileInfo -> String Source #

Pack the permissions into a string, similar to what "ls -l" does.

packFileType :: File a -> String Source #

fromFreeVar :: Default d => (a -> d) -> File a -> d Source #

Apply a function on the free variable. If there is no free variable + for the given constructor the value from the Default class is used.

getFPasStr :: File a -> String Source #

getFreeVar :: File a -> Maybe a Source #

Gets the free variable. Returns Nothing if the constructor is of Failed.

\ No newline at end of file diff --git a/HSFM-FileSystem-UtilTypes.html b/HSFM-FileSystem-UtilTypes.html new file mode 100644 index 0000000..3696e98 --- /dev/null +++ b/HSFM-FileSystem-UtilTypes.html @@ -0,0 +1,18 @@ +HSFM.FileSystem.UtilTypes

hsfm-gtk

Safe HaskellSafe
LanguageHaskell2010

HSFM.FileSystem.UtilTypes

Description

This module provides high-level IO related file operations like + copy, delete, move and so on. It only operates on `Path Abs` which + guarantees us well-typed paths which are absolute.

Some functions are just path-safe wrappers around + unix functions, others have stricter exception handling + and some implement functionality that doesn't have a unix + counterpart (like copyDirRecursive).

Some of these operations are due to their nature not _atomic_, which + means they may do multiple syscalls which form one context. Some + of them also have to examine the filetypes explicitly before the + syscalls, so a reasonable decision can be made. That means + the result is undefined if another process changes that context + while the non-atomic operation is still happening. However, where + possible, as few syscalls as possible are used and the underlying + exception handling is kept.

Synopsis

Documentation

data FileOperation Source #

Data type describing file operations. + Useful to build up a list of operations or delay operations.

Constructors

FCopy Copy 
FMove Move 
FDelete [Path Abs] 
FOpen (Path Abs) 
FExecute (Path Abs) [ByteString] 
None 

data Copy Source #

Data type describing partial or complete file copy operation.

Constructors

PartialCopy [Path Abs] 
Copy [Path Abs] (Path Abs) 

data Move Source #

Data type describing partial or complete file move operation.

Constructors

PartialMove [Path Abs] 
Move [Path Abs] (Path Abs) 

data FCollisonMode Source #

Collision modes that describe the behavior in case a file collision + happens.

Constructors

Strict

fail if the target already exists

Overwrite 
OverwriteAll 
Skip 
Rename (Path Fn) 
\ No newline at end of file diff --git a/HSFM-GUI-Glib-GlibString.html b/HSFM-GUI-Glib-GlibString.html new file mode 100644 index 0000000..d15cce4 --- /dev/null +++ b/HSFM-GUI-Glib-GlibString.html @@ -0,0 +1,4 @@ +HSFM.GUI.Glib.GlibString

hsfm-gtk

Safe HaskellNone
LanguageHaskell2010

HSFM.GUI.Glib.GlibString

Documentation

c_strlen :: CString -> IO CSize Source #

noNullPtrs :: CStringLen -> CStringLen Source #

Orphan instances

GlibString ByteString Source # 

Methods

withUTFString :: ByteString -> (CString -> IO a) -> IO a

withUTFStringLen :: ByteString -> (CStringLen -> IO a) -> IO a

peekUTFString :: CString -> IO ByteString

maybePeekUTFString :: CString -> IO (Maybe ByteString)

peekUTFStringLen :: CStringLen -> IO ByteString

newUTFString :: ByteString -> IO CString

newUTFStringLen :: ByteString -> IO CStringLen

genUTFOfs :: ByteString -> UTFCorrection

stringLength :: ByteString -> Int

unPrintf :: ByteString -> ByteString

\ No newline at end of file diff --git a/HSFM-GUI-Gtk-Callbacks-Utils.html b/HSFM-GUI-Gtk-Callbacks-Utils.html new file mode 100644 index 0000000..3cf6cfb --- /dev/null +++ b/HSFM-GUI-Gtk-Callbacks-Utils.html @@ -0,0 +1,5 @@ +HSFM.GUI.Gtk.Callbacks.Utils

hsfm-gtk

Safe HaskellNone
LanguageHaskell2010

HSFM.GUI.Gtk.Callbacks.Utils

Synopsis

Documentation

doFileOperation :: FileOperation -> IO () Source #

Carries out a file operation with the appropriate error handling + allowing the user to react to various exceptions with further input.

_doFileOperation :: [Path b1] -> Path Abs -> (Path b1 -> Path Abs -> IO b) -> (Path b1 -> Path Abs -> IO a) -> IO () -> IO () Source #

goDir :: MyGUI -> MyView -> Item -> IO () Source #

Helper that is invoked for any directory change operations.

\ No newline at end of file diff --git a/HSFM-GUI-Gtk-Callbacks.html b/HSFM-GUI-Gtk-Callbacks.html new file mode 100644 index 0000000..d1e6914 --- /dev/null +++ b/HSFM-GUI-Gtk-Callbacks.html @@ -0,0 +1,5 @@ +HSFM.GUI.Gtk.Callbacks

hsfm-gtk

Safe HaskellNone
LanguageHaskell2010

HSFM.GUI.Gtk.Callbacks

Synopsis

Documentation

setGUICallbacks :: MyGUI -> IO () Source #

Set callbacks for the whole gui, on hotkeys, events and stuff.

setViewCallbacks :: MyGUI -> MyView -> IO () Source #

Set callbacks specific to a given view, on hotkeys, events and stuff.

openTerminalHere :: MyView -> IO ProcessID Source #

closeTab :: MyGUI -> MyView -> IO () Source #

Closes the current tab, but only if there is more than one tab.

newTabHere :: MyGUI -> MyView -> [Item] -> IO () Source #

del :: [Item] -> MyGUI -> MyView -> IO () Source #

Supposed to be used with withRows. Deletes a file or directory.

moveInit :: [Item] -> MyGUI -> MyView -> IO () Source #

Initializes a file move operation.

copyInit :: [Item] -> MyGUI -> MyView -> IO () Source #

Supposed to be used with withRows. Initializes a file copy operation.

operationFinal :: MyGUI -> MyView -> Maybe Item -> IO () Source #

Finalizes a file operation, such as copy or move.

newFile :: MyGUI -> MyView -> IO () Source #

Create a new file.

newDir :: MyGUI -> MyView -> IO () Source #

Create a new directory.

renameF :: [Item] -> MyGUI -> MyView -> IO () Source #

urlGoTo :: MyGUI -> MyView -> IO () Source #

Go to the url given at the urlBar and visualize it in the given + treeView.

If the url is invalid, does nothing.

goHome :: MyGUI -> MyView -> IO () Source #

execute :: [Item] -> MyGUI -> MyView -> IO () Source #

Execute a given file.

open :: [Item] -> MyGUI -> MyView -> IO () Source #

Supposed to be used with withRows. Opens a file or directory.

upDir :: MyGUI -> MyView -> IO () Source #

Go up one directory and visualize it in the treeView.

goHistoryPrev :: MyGUI -> MyView -> IO () Source #

Go "back" in the history.

goHistoryNext :: MyGUI -> MyView -> IO () Source #

Go "forth" in the history.

\ No newline at end of file diff --git a/HSFM-GUI-Gtk-Data.html b/HSFM-GUI-Gtk-Data.html new file mode 100644 index 0000000..0ad4cad --- /dev/null +++ b/HSFM-GUI-Gtk-Data.html @@ -0,0 +1,8 @@ +HSFM.GUI.Gtk.Data

hsfm-gtk

Safe HaskellNone
LanguageHaskell2010

HSFM.GUI.Gtk.Data

Synopsis

Documentation

data MyGUI Source #

Monolithic object passed to various GUI functions in order + to keep the API stable and not alter the parameters too much. + This only holds GUI widgets that are needed to be read during + runtime.

Constructors

MkMyGUI 

Fields

data MyView Source #

This describes the contents of the current view and is separated from MyGUI, + because we might want to have multiple views.

Constructors

MkMyView 

Fields

data MenuBar Source #

Constructors

MkMenuBar 

Fields

data RightClickMenu Source #

Constructors

MkRightClickMenu 

Fields

data FilePropertyGrid Source #

Constructors

MkFilePropertyGrid 

Fields

data FMSettings Source #

FM-wide settings.

Constructors

MkFMSettings 

Fields

data FMView Source #

Constructors

FMTreeView !TreeView 
FMIconView !IconView 
\ No newline at end of file diff --git a/HSFM-GUI-Gtk-Dialogs.html b/HSFM-GUI-Gtk-Dialogs.html new file mode 100644 index 0000000..997adc0 --- /dev/null +++ b/HSFM-GUI-Gtk-Dialogs.html @@ -0,0 +1,7 @@ +HSFM.GUI.Gtk.Dialogs

hsfm-gtk

Safe HaskellNone
LanguageHaskell2010

HSFM.GUI.Gtk.Dialogs

Synopsis

Documentation

showErrorDialog :: String -> IO () Source #

Pops up an error Dialog with the given String.

showConfirmationDialog :: String -> IO Bool Source #

Asks the user for confirmation and returns True/False.

showAboutDialog :: IO () Source #

Shows the about dialog from the help menu.

withConfirmationDialog :: String -> IO () -> IO () Source #

Carry out an IO action with a confirmation dialog. + If the user presses No, then do nothing.

withErrorDialog :: IO a -> IO () Source #

Execute the given IO action. If the action throws exceptions, + visualize them via showErrorDialog.

textInputDialog Source #

Arguments

:: GlibString string 
=> string

window title

-> string

initial text in input widget

-> IO (Maybe String) 

Asks the user which directory copy mode he wants via dialog popup + and returns DirCopyMode.

\ No newline at end of file diff --git a/HSFM-GUI-Gtk-Errors.html b/HSFM-GUI-Gtk-Errors.html new file mode 100644 index 0000000..6d0a1f7 --- /dev/null +++ b/HSFM-GUI-Gtk-Errors.html @@ -0,0 +1,4 @@ +HSFM.GUI.Gtk.Errors

hsfm-gtk

Safe HaskellSafe
LanguageHaskell2010

HSFM.GUI.Gtk.Errors

Description

Provides error handling for Gtk.

Documentation

data GtkException Source #

Constructors

UnknownDialogButton 

Instances

Show GtkException Source # 

Methods

showsPrec :: Int -> GtkException -> ShowS

show :: GtkException -> String

showList :: [GtkException] -> ShowS

Exception GtkException Source # 

Methods

toException :: GtkException -> SomeException

fromException :: SomeException -> Maybe GtkException

displayException :: GtkException -> String

\ No newline at end of file diff --git a/HSFM-GUI-Gtk-Icons.html b/HSFM-GUI-Gtk-Icons.html new file mode 100644 index 0000000..1af4c5b --- /dev/null +++ b/HSFM-GUI-Gtk-Icons.html @@ -0,0 +1,5 @@ +HSFM.GUI.Gtk.Icons

hsfm-gtk

Safe HaskellNone
LanguageHaskell2010

HSFM.GUI.Gtk.Icons

Description

Module for Gtk icon handling.

Synopsis

Documentation

data GtkIcon Source #

Icon type we use in our GUI.

Constructors

IFolder 
SymL 
IFile 
IError 

getIcon Source #

Arguments

:: GtkIcon

icon we want

-> IconTheme

which icon theme to get the icon from

-> Int

requested icon size

-> IO Pixbuf 

Gets an icon from the default icon theme and falls back to project-icons + if not found. The requested icon size is not guaranteed.

getSymlinkIcon :: GtkIcon -> IconTheme -> Int -> IO Pixbuf Source #

\ No newline at end of file diff --git a/HSFM-GUI-Gtk-MyGUI.html b/HSFM-GUI-Gtk-MyGUI.html new file mode 100644 index 0000000..a1aaab1 --- /dev/null +++ b/HSFM-GUI-Gtk-MyGUI.html @@ -0,0 +1,4 @@ +HSFM.GUI.Gtk.MyGUI

hsfm-gtk

Safe HaskellNone
LanguageHaskell2010

HSFM.GUI.Gtk.MyGUI

Synopsis

Documentation

createMyGUI :: IO MyGUI Source #

Set up the GUI. This only creates the permanent widgets.

\ No newline at end of file diff --git a/HSFM-GUI-Gtk-MyView.html b/HSFM-GUI-Gtk-MyView.html new file mode 100644 index 0000000..b317f79 --- /dev/null +++ b/HSFM-GUI-Gtk-MyView.html @@ -0,0 +1,14 @@ +HSFM.GUI.Gtk.MyView

hsfm-gtk

Safe HaskellNone
LanguageHaskell2010

HSFM.GUI.Gtk.MyView

Synopsis

Documentation

newTab :: MyGUI -> IO FMView -> Path Abs -> IO MyView Source #

Creates a new tab with its own view and refreshes the view.

createMyView :: MyGUI -> IO FMView -> IO MyView Source #

Constructs the initial MyView object with a few dummy models. + It also initializes the callbacks.

switchView :: MyGUI -> MyView -> IO FMView -> IO () Source #

Switch the existing view in MyView with the one that the + io action returns.

destroyView :: MyGUI -> MyView -> IO Int Source #

Destroys the current view by disconnecting the watcher + and destroying the active FMView container.

Everything that needs to be done in order to forget about a + view needs to be done here.

Returns the page in the tab list this view corresponds to.

createIconView :: IO FMView Source #

Createss an IconView.

createTreeView :: IO FMView Source #

Creates a TreeView.

refreshView :: MyGUI -> MyView -> Maybe (Path Abs) -> IO () Source #

Re-reads the current directory or the given one and updates the View. + This is more or less a wrapper around refreshView'

If the third argument is Nothing, it tries to re-read the current directory. + If that fails, it reads "/" instead.

If the third argument is (Just path) it tries to read "path". If that + fails, it reads "/" instead.

refreshView' :: MyGUI -> MyView -> Item -> IO () Source #

Refreshes the View based on the given directory.

If the directory is not a Dir or a Symlink pointing to a Dir, then + calls refreshView with the 3rd argument being Nothing.

constructView :: MyGUI -> MyView -> IO () Source #

Constructs the visible View with the current underlying mutable models, + which are retrieved from MyGUI.

This sort of merges the components mygui and myview and fires up + the actual models.

\ No newline at end of file diff --git a/HSFM-GUI-Gtk-Utils.html b/HSFM-GUI-Gtk-Utils.html new file mode 100644 index 0000000..c6cfbc1 --- /dev/null +++ b/HSFM-GUI-Gtk-Utils.html @@ -0,0 +1,11 @@ +HSFM.GUI.Gtk.Utils

hsfm-gtk

Safe HaskellNone
LanguageHaskell2010

HSFM.GUI.Gtk.Utils

Synopsis

Documentation

getSelectedTreePaths :: MyGUI -> MyView -> IO [TreePath] Source #

getSelectedItems :: MyGUI -> MyView -> IO [Item] Source #

Gets the currently selected item of the treeView, if any.

withItems Source #

Arguments

:: MyGUI 
-> MyView 
-> ([Item] -> MyGUI -> MyView -> IO ())

action to carry out

-> IO () 

Carry out an action on the currently selected item.

If there is no item selected, does nothing.

fileListStore Source #

Arguments

:: Item

current dir

-> MyView 
-> IO (ListStore Item) 

Create the ListStore of files/directories from the current directory. + This is the function which maps the Data.DirTree data structures + into the GTK+ data structures.

getFirstItem :: MyView -> IO Item Source #

Currently unsafe. This is used to obtain any item, which will + fail if there is none.

getCurrentDir :: MyView -> IO Item Source #

Reads the current directory from MyView.

This reads the MVar and may block the main thread if it's + empty.

pushStatusBar :: MyGUI -> String -> IO (ContextId, MessageId) Source #

Push a message to the status bar.

popStatusbar :: MyGUI -> IO () Source #

Pop a message from the status bar.

rawPathToIter :: MyView -> TreePath -> IO (Maybe TreeIter) Source #

Turn a path on the rawModel into a path that we can + use at the outermost model layer.

rawPathToItem :: MyView -> TreePath -> IO (Maybe Item) Source #

Turn a path on the rawModel into the corresponding item + that we can use at the outermost model layer.

addHistory :: Eq a => a -> [a] -> [a] Source #

Makes sure the list is max 5. This is probably not very efficient + but we don't care, since it's a small list anyway.

\ No newline at end of file diff --git a/HSFM-Utils-IO.html b/HSFM-Utils-IO.html new file mode 100644 index 0000000..77562e1 --- /dev/null +++ b/HSFM-Utils-IO.html @@ -0,0 +1,4 @@ +HSFM.Utils.IO

hsfm-gtk

Safe HaskellSafe
LanguageHaskell2010

HSFM.Utils.IO

Description

Random and general IO utilities.

Synopsis

Documentation

writeTVarIO :: TVar a -> a -> IO () Source #

Atomically write a TVar.

modifyTVarIO :: TVar a -> (a -> a) -> IO () Source #

Atomically modify a TVar.

\ No newline at end of file diff --git a/HSFM-Utils-MyPrelude.html b/HSFM-Utils-MyPrelude.html new file mode 100644 index 0000000..f8a70a5 --- /dev/null +++ b/HSFM-Utils-MyPrelude.html @@ -0,0 +1,6 @@ +HSFM.Utils.MyPrelude

hsfm-gtk

Safe HaskellNone
LanguageHaskell2010

HSFM.Utils.MyPrelude

Synopsis

Documentation

listIndices :: [a] -> [Int] Source #

Turns any list into a list of the same length with the values + being the indices. + E.g.: "abdasd" -> [0,1,2,3,4,5]

maybeD :: Default b => (a -> b) -> Maybe a -> b Source #

A maybe flavor using the Default class.

\ No newline at end of file diff --git a/Main.html b/Main.html new file mode 100644 index 0000000..06224c1 --- /dev/null +++ b/Main.html @@ -0,0 +1,4 @@ +Main

hsfm-gtk

Safe HaskellNone
LanguageHaskell2010

Main

Documentation

main :: IO () Source #

\ No newline at end of file diff --git a/Paths_hsfm.html b/Paths_hsfm.html new file mode 100644 index 0000000..9af005c --- /dev/null +++ b/Paths_hsfm.html @@ -0,0 +1,4 @@ +Paths_hsfm

hsfm-gtk

Safe HaskellSafe
LanguageHaskell2010

Paths_hsfm

Documentation

version :: Version Source #

getBinDir :: IO FilePath Source #

getLibDir :: IO FilePath Source #

getDataDir :: IO FilePath Source #

getLibexecDir :: IO FilePath Source #

getDataFileName :: FilePath -> IO FilePath Source #

getSysconfDir :: IO FilePath Source #

\ No newline at end of file diff --git a/doc-index-95.html b/doc-index-95.html new file mode 100644 index 0000000..ff7d273 --- /dev/null +++ b/doc-index-95.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - _)

hsfm-gtk

Index - _

_doFileOperationHSFM.GUI.Gtk.Callbacks.Utils
\ No newline at end of file diff --git a/doc-index-A.html b/doc-index-A.html new file mode 100644 index 0000000..85d80e8 --- /dev/null +++ b/doc-index-A.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - A)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-All.html b/doc-index-All.html new file mode 100644 index 0000000..4640cdb --- /dev/null +++ b/doc-index-All.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index)

hsfm-gtk

Index

accessTimeHSFM.FileSystem.FileType
accessTimeHiResHSFM.FileSystem.FileType
addHistoryHSFM.GUI.Gtk.Utils
anyFailedHSFM.FileSystem.FileType
BlockDevHSFM.FileSystem.FileType
BrokenSymlinkHSFM.FileSystem.FileType
brokenSymlinkHSFM.FileSystem.FileType
CharDevHSFM.FileSystem.FileType
clearStatusBarHSFM.GUI.Gtk.Data
closeTabHSFM.GUI.Gtk.Callbacks
comparingConstrHSFM.FileSystem.FileType
constructViewHSFM.GUI.Gtk.MyView
Copy 
1 (Type/Class)HSFM.FileSystem.UtilTypes
2 (Data Constructor)HSFM.FileSystem.UtilTypes
copyInitHSFM.GUI.Gtk.Callbacks
createIconViewHSFM.GUI.Gtk.MyView
createMyGUIHSFM.GUI.Gtk.MyGUI
createMyViewHSFM.GUI.Gtk.MyView
createTreeViewHSFM.GUI.Gtk.MyView
cwdHSFM.GUI.Gtk.Data
c_strlenHSFM.GUI.Glib.GlibString
delHSFM.GUI.Gtk.Callbacks
destroyViewHSFM.GUI.Gtk.MyView
deviceIDHSFM.FileSystem.FileType
DirHSFM.FileSystem.FileType
DirListHSFM.FileSystem.FileType
DirOrSymHSFM.FileSystem.FileType
DirSymHSFM.FileSystem.FileType
dirSymHSFM.FileSystem.FileType
doFileOperationHSFM.GUI.Gtk.Callbacks.Utils
epochToStringHSFM.FileSystem.FileType
errHSFM.FileSystem.FileType
executeHSFM.GUI.Gtk.Callbacks
FailedHSFM.FileSystem.FileType
failedHSFM.FileSystem.FileType
failuresHSFM.FileSystem.FileType
FCollisonModeHSFM.FileSystem.UtilTypes
FCopyHSFM.FileSystem.UtilTypes
FDeleteHSFM.FileSystem.UtilTypes
FExecuteHSFM.FileSystem.UtilTypes
FileHSFM.FileSystem.FileType
fileCollisionDialogHSFM.GUI.Gtk.Dialogs
fileGroupHSFM.FileSystem.FileType
fileIDHSFM.FileSystem.FileType
FileInfo 
1 (Type/Class)HSFM.FileSystem.FileType
2 (Data Constructor)HSFM.FileSystem.FileType
FileLikeHSFM.FileSystem.FileType
fileLikeHSFM.FileSystem.FileType
FileLikeListHSFM.FileSystem.FileType
FileLikeOrSymHSFM.FileSystem.FileType
FileLikeSymHSFM.FileSystem.FileType
fileLikeSymHSFM.FileSystem.FileType
fileListStoreHSFM.GUI.Gtk.Utils
fileModeHSFM.FileSystem.FileType
FileOperationHSFM.FileSystem.UtilTypes
fileOwnerHSFM.FileSystem.FileType
FilePropertyGridHSFM.GUI.Gtk.Data
fileSizeHSFM.FileSystem.FileType
filteredModelHSFM.GUI.Gtk.Data
FMIconViewHSFM.GUI.Gtk.Data
FMoveHSFM.FileSystem.UtilTypes
FMSettingsHSFM.GUI.Gtk.Data
FMTreeViewHSFM.GUI.Gtk.Data
FMViewHSFM.GUI.Gtk.Data
fmViewToContainerHSFM.GUI.Gtk.Data
FOpenHSFM.FileSystem.UtilTypes
fpropHSFM.GUI.Gtk.Data
fpropAcEntryHSFM.GUI.Gtk.Data
fpropFnEntryHSFM.GUI.Gtk.Data
fpropFTEntryHSFM.GUI.Gtk.Data
fpropGridHSFM.GUI.Gtk.Data
fpropLDEntryHSFM.GUI.Gtk.Data
fpropLocEntryHSFM.GUI.Gtk.Data
fpropModEntryHSFM.GUI.Gtk.Data
fpropPermEntryHSFM.GUI.Gtk.Data
fpropTsEntryHSFM.GUI.Gtk.Data
fromFreeVarHSFM.FileSystem.FileType
fvarHSFM.FileSystem.FileType
getBinDirPaths_hsfm
getContentsHSFM.FileSystem.FileType
getCurrentDirHSFM.GUI.Gtk.Utils
getDataDirPaths_hsfm
getDataFileNamePaths_hsfm
getFileInfoHSFM.FileSystem.FileType
getFirstItemHSFM.GUI.Gtk.Utils
getFPasStrHSFM.FileSystem.FileType
getFreeVarHSFM.FileSystem.FileType
getIconHSFM.GUI.Gtk.Icons
getLibDirPaths_hsfm
getLibexecDirPaths_hsfm
getSelectedItemsHSFM.GUI.Gtk.Utils
getSelectedTreePathsHSFM.GUI.Gtk.Utils
getSymlinkIconHSFM.GUI.Gtk.Icons
getSysconfDirPaths_hsfm
goDirHSFM.GUI.Gtk.Callbacks.Utils
goHistoryNextHSFM.GUI.Gtk.Callbacks
goHistoryPrevHSFM.GUI.Gtk.Callbacks
goHomeHSFM.GUI.Gtk.Callbacks
goUpHSFM.FileSystem.FileType
goUp'HSFM.FileSystem.FileType
GtkExceptionHSFM.GUI.Gtk.Errors
GtkIconHSFM.GUI.Gtk.Icons
handleDTHSFM.FileSystem.FileType
historyHSFM.GUI.Gtk.Data
homeViewBHSFM.GUI.Gtk.Data
iconSizeHSFM.GUI.Gtk.Data
IErrorHSFM.GUI.Gtk.Icons
IFileHSFM.GUI.Gtk.Icons
IFolderHSFM.GUI.Gtk.Icons
inotifyHSFM.GUI.Gtk.Data
isBlockCHSFM.FileSystem.FileType
isBrokenSymlinkHSFM.FileSystem.FileType
isCharCHSFM.FileSystem.FileType
isDirCHSFM.FileSystem.FileType
isFileCHSFM.FileSystem.FileType
isLazyHSFM.GUI.Gtk.Data
isNamedCHSFM.FileSystem.FileType
isSocketCHSFM.FileSystem.FileType
isSymCHSFM.FileSystem.FileType
ItemHSFM.GUI.Gtk.Data
linkCountHSFM.FileSystem.FileType
listIndicesHSFM.Utils.MyPrelude
mainMain
maybeDHSFM.Utils.MyPrelude
MenuBarHSFM.GUI.Gtk.Data
menubarHSFM.GUI.Gtk.Data
menubarFileQuitHSFM.GUI.Gtk.Data
menubarHelpAboutHSFM.GUI.Gtk.Data
MkFilePropertyGridHSFM.GUI.Gtk.Data
MkFMSettingsHSFM.GUI.Gtk.Data
MkMenuBarHSFM.GUI.Gtk.Data
MkMyGUIHSFM.GUI.Gtk.Data
MkMyViewHSFM.GUI.Gtk.Data
MkRightClickMenuHSFM.GUI.Gtk.Data
modificationTimeHSFM.FileSystem.FileType
modificationTimeHiResHSFM.FileSystem.FileType
modifyTVarIOHSFM.Utils.IO
Move 
1 (Type/Class)HSFM.FileSystem.UtilTypes
2 (Data Constructor)HSFM.FileSystem.UtilTypes
moveInitHSFM.GUI.Gtk.Callbacks
MyGUIHSFM.GUI.Gtk.Data
MyViewHSFM.GUI.Gtk.Data
NamedPipeHSFM.FileSystem.FileType
newDirHSFM.GUI.Gtk.Callbacks
newFileHSFM.GUI.Gtk.Callbacks
newTabHSFM.GUI.Gtk.MyView
newTabHereHSFM.GUI.Gtk.Callbacks
NoneHSFM.FileSystem.UtilTypes
noNullPtrsHSFM.GUI.Glib.GlibString
notebookHSFM.GUI.Gtk.Data
openHSFM.GUI.Gtk.Callbacks
openTerminalHereHSFM.GUI.Gtk.Callbacks
operationBufferHSFM.GUI.Gtk.Data
operationFinalHSFM.GUI.Gtk.Callbacks
OverwriteHSFM.FileSystem.UtilTypes
OverwriteAllHSFM.FileSystem.UtilTypes
packAccessTimeHSFM.FileSystem.FileType
packFileTypeHSFM.FileSystem.FileType
packLinkDestinationHSFM.FileSystem.FileType
packModTimeHSFM.FileSystem.FileType
packPermissionsHSFM.FileSystem.FileType
PartialCopyHSFM.FileSystem.UtilTypes
PartialMoveHSFM.FileSystem.UtilTypes
pathHSFM.FileSystem.FileType
popStatusbarHSFM.GUI.Gtk.Utils
pushStatusBarHSFM.GUI.Gtk.Utils
rawdestHSFM.FileSystem.FileType
rawModelHSFM.GUI.Gtk.Data
rawPathToItemHSFM.GUI.Gtk.Utils
rawPathToIterHSFM.GUI.Gtk.Utils
rcFileCopyHSFM.GUI.Gtk.Data
rcFileCutHSFM.GUI.Gtk.Data
rcFileDeleteHSFM.GUI.Gtk.Data
rcFileExecuteHSFM.GUI.Gtk.Data
rcFileIconViewHSFM.GUI.Gtk.Data
rcFileNewDirHSFM.GUI.Gtk.Data
rcFileNewRegFileHSFM.GUI.Gtk.Data
rcFileOpenHSFM.GUI.Gtk.Data
rcFilePasteHSFM.GUI.Gtk.Data
rcFilePropertyHSFM.GUI.Gtk.Data
rcFileRenameHSFM.GUI.Gtk.Data
rcFileTreeViewHSFM.GUI.Gtk.Data
rcMenuHSFM.GUI.Gtk.Data
rcmenuHSFM.GUI.Gtk.Data
readDirectoryContentsHSFM.FileSystem.FileType
readFileHSFM.FileSystem.FileType
refreshViewHSFM.GUI.Gtk.MyView
refreshView'HSFM.GUI.Gtk.MyView
refreshViewBHSFM.GUI.Gtk.Data
RegFileHSFM.FileSystem.FileType
RenameHSFM.FileSystem.UtilTypes
renameDialogHSFM.GUI.Gtk.Dialogs
renameFHSFM.GUI.Gtk.Callbacks
RightClickMenuHSFM.GUI.Gtk.Data
rootWinHSFM.GUI.Gtk.Data
scrollHSFM.GUI.Gtk.Data
sdestHSFM.FileSystem.FileType
sdirHSFM.FileSystem.FileType
setGUICallbacksHSFM.GUI.Gtk.Callbacks
settingsHSFM.GUI.Gtk.Data
setViewCallbacksHSFM.GUI.Gtk.Callbacks
sfileLikeHSFM.FileSystem.FileType
showAboutDialogHSFM.GUI.Gtk.Dialogs
showConfirmationDialogHSFM.GUI.Gtk.Dialogs
showErrorDialogHSFM.GUI.Gtk.Dialogs
showFilePropertyDialogHSFM.GUI.Gtk.Dialogs
showHiddenHSFM.GUI.Gtk.Data
SkipHSFM.FileSystem.UtilTypes
SocketHSFM.FileSystem.FileType
sortedModelHSFM.GUI.Gtk.Data
specialDeviceIDHSFM.FileSystem.FileType
statusBarHSFM.GUI.Gtk.Data
statusChangeTimeHSFM.FileSystem.FileType
statusChangeTimeHiResHSFM.FileSystem.FileType
StrictHSFM.FileSystem.UtilTypes
successfulHSFM.FileSystem.FileType
switchViewHSFM.GUI.Gtk.MyView
SymLHSFM.GUI.Gtk.Icons
SymLinkHSFM.FileSystem.FileType
textInputDialogHSFM.GUI.Gtk.Dialogs
UnknownDialogButtonHSFM.GUI.Gtk.Errors
upDirHSFM.GUI.Gtk.Callbacks
upViewBHSFM.GUI.Gtk.Data
urlBarHSFM.GUI.Gtk.Data
urlGoToHSFM.GUI.Gtk.Callbacks
versionPaths_hsfm
viewHSFM.GUI.Gtk.Data
viewBoxHSFM.GUI.Gtk.Data
withConfirmationDialogHSFM.GUI.Gtk.Dialogs
withErrorDialogHSFM.GUI.Gtk.Dialogs
withItemsHSFM.GUI.Gtk.Utils
writeTVarIOHSFM.Utils.IO
_doFileOperationHSFM.GUI.Gtk.Callbacks.Utils
\ No newline at end of file diff --git a/doc-index-B.html b/doc-index-B.html new file mode 100644 index 0000000..410ef5a --- /dev/null +++ b/doc-index-B.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - B)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-C.html b/doc-index-C.html new file mode 100644 index 0000000..4d62096 --- /dev/null +++ b/doc-index-C.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - C)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-D.html b/doc-index-D.html new file mode 100644 index 0000000..a11f81e --- /dev/null +++ b/doc-index-D.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - D)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-E.html b/doc-index-E.html new file mode 100644 index 0000000..c3685c1 --- /dev/null +++ b/doc-index-E.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - E)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-F.html b/doc-index-F.html new file mode 100644 index 0000000..947a05a --- /dev/null +++ b/doc-index-F.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - F)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-G.html b/doc-index-G.html new file mode 100644 index 0000000..856f06c --- /dev/null +++ b/doc-index-G.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - G)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-H.html b/doc-index-H.html new file mode 100644 index 0000000..cd4f2cc --- /dev/null +++ b/doc-index-H.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - H)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-I.html b/doc-index-I.html new file mode 100644 index 0000000..975e1e0 --- /dev/null +++ b/doc-index-I.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - I)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-L.html b/doc-index-L.html new file mode 100644 index 0000000..e5715a5 --- /dev/null +++ b/doc-index-L.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - L)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-M.html b/doc-index-M.html new file mode 100644 index 0000000..425ce5d --- /dev/null +++ b/doc-index-M.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - M)

hsfm-gtk

Index - M

mainMain
maybeDHSFM.Utils.MyPrelude
MenuBarHSFM.GUI.Gtk.Data
menubarHSFM.GUI.Gtk.Data
menubarFileQuitHSFM.GUI.Gtk.Data
menubarHelpAboutHSFM.GUI.Gtk.Data
MkFilePropertyGridHSFM.GUI.Gtk.Data
MkFMSettingsHSFM.GUI.Gtk.Data
MkMenuBarHSFM.GUI.Gtk.Data
MkMyGUIHSFM.GUI.Gtk.Data
MkMyViewHSFM.GUI.Gtk.Data
MkRightClickMenuHSFM.GUI.Gtk.Data
modificationTimeHSFM.FileSystem.FileType
modificationTimeHiResHSFM.FileSystem.FileType
modifyTVarIOHSFM.Utils.IO
Move 
1 (Type/Class)HSFM.FileSystem.UtilTypes
2 (Data Constructor)HSFM.FileSystem.UtilTypes
moveInitHSFM.GUI.Gtk.Callbacks
MyGUIHSFM.GUI.Gtk.Data
MyViewHSFM.GUI.Gtk.Data
\ No newline at end of file diff --git a/doc-index-N.html b/doc-index-N.html new file mode 100644 index 0000000..bafb9a6 --- /dev/null +++ b/doc-index-N.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - N)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-O.html b/doc-index-O.html new file mode 100644 index 0000000..8dc9855 --- /dev/null +++ b/doc-index-O.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - O)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-P.html b/doc-index-P.html new file mode 100644 index 0000000..bb2b7cf --- /dev/null +++ b/doc-index-P.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - P)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-R.html b/doc-index-R.html new file mode 100644 index 0000000..349d1ea --- /dev/null +++ b/doc-index-R.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - R)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-S.html b/doc-index-S.html new file mode 100644 index 0000000..56b0d88 --- /dev/null +++ b/doc-index-S.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - S)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-T.html b/doc-index-T.html new file mode 100644 index 0000000..5885ec4 --- /dev/null +++ b/doc-index-T.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - T)

hsfm-gtk

Index - T

textInputDialogHSFM.GUI.Gtk.Dialogs
\ No newline at end of file diff --git a/doc-index-U.html b/doc-index-U.html new file mode 100644 index 0000000..7692db4 --- /dev/null +++ b/doc-index-U.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - U)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-V.html b/doc-index-V.html new file mode 100644 index 0000000..5abda33 --- /dev/null +++ b/doc-index-V.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - V)

hsfm-gtk

\ No newline at end of file diff --git a/doc-index-W.html b/doc-index-W.html new file mode 100644 index 0000000..84d802c --- /dev/null +++ b/doc-index-W.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index - W)

hsfm-gtk

Index - W

withConfirmationDialogHSFM.GUI.Gtk.Dialogs
withErrorDialogHSFM.GUI.Gtk.Dialogs
withItemsHSFM.GUI.Gtk.Utils
writeTVarIOHSFM.Utils.IO
\ No newline at end of file diff --git a/doc-index.html b/doc-index.html new file mode 100644 index 0000000..50bf15e --- /dev/null +++ b/doc-index.html @@ -0,0 +1,4 @@ +hsfm-gtk (Index)

hsfm-gtk

\ No newline at end of file diff --git a/frames.html b/frames.html new file mode 100644 index 0000000..e86edb6 --- /dev/null +++ b/frames.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + diff --git a/haddock-util.js b/haddock-util.js new file mode 100644 index 0000000..fc7743f --- /dev/null +++ b/haddock-util.js @@ -0,0 +1,344 @@ +// Haddock JavaScript utilities + +var rspace = /\s\s+/g, + rtrim = /^\s+|\s+$/g; + +function spaced(s) { return (" " + s + " ").replace(rspace, " "); } +function trim(s) { return s.replace(rtrim, ""); } + +function hasClass(elem, value) { + var className = spaced(elem.className || ""); + return className.indexOf( " " + value + " " ) >= 0; +} + +function addClass(elem, value) { + var className = spaced(elem.className || ""); + if ( className.indexOf( " " + value + " " ) < 0 ) { + elem.className = trim(className + " " + value); + } +} + +function removeClass(elem, value) { + var className = spaced(elem.className || ""); + className = className.replace(" " + value + " ", " "); + elem.className = trim(className); +} + +function toggleClass(elem, valueOn, valueOff, bool) { + if (bool == null) { bool = ! hasClass(elem, valueOn); } + if (bool) { + removeClass(elem, valueOff); + addClass(elem, valueOn); + } + else { + removeClass(elem, valueOn); + addClass(elem, valueOff); + } + return bool; +} + + +function makeClassToggle(valueOn, valueOff) +{ + return function(elem, bool) { + return toggleClass(elem, valueOn, valueOff, bool); + } +} + +toggleShow = makeClassToggle("show", "hide"); +toggleCollapser = makeClassToggle("collapser", "expander"); + +function toggleSection(id) +{ + var b = toggleShow(document.getElementById("section." + id)); + toggleCollapser(document.getElementById("control." + id), b); + rememberCollapsed(id, b); + return b; +} + +var collapsed = {}; +function rememberCollapsed(id, b) +{ + if(b) + delete collapsed[id] + else + collapsed[id] = null; + + var sections = []; + for(var i in collapsed) + { + if(collapsed.hasOwnProperty(i)) + sections.push(i); + } + // cookie specific to this page; don't use setCookie which sets path=/ + document.cookie = "collapsed=" + escape(sections.join('+')); +} + +function restoreCollapsed() +{ + var cookie = getCookie("collapsed"); + if(!cookie) + return; + + var ids = cookie.split('+'); + for(var i in ids) + { + if(document.getElementById("section." + ids[i])) + toggleSection(ids[i]); + } +} + +function setCookie(name, value) { + document.cookie = name + "=" + escape(value) + ";path=/;"; +} + +function clearCookie(name) { + document.cookie = name + "=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT;"; +} + +function getCookie(name) { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + for(var i=0;i < ca.length;i++) { + var c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1,c.length); + if (c.indexOf(nameEQ) == 0) { + return unescape(c.substring(nameEQ.length,c.length)); + } + } + return null; +} + + + +var max_results = 75; // 50 is not enough to search for map in the base libraries +var shown_range = null; +var last_search = null; + +function quick_search() +{ + perform_search(false); +} + +function full_search() +{ + perform_search(true); +} + + +function perform_search(full) +{ + var text = document.getElementById("searchbox").value.toLowerCase(); + if (text == last_search && !full) return; + last_search = text; + + var table = document.getElementById("indexlist"); + var status = document.getElementById("searchmsg"); + var children = table.firstChild.childNodes; + + // first figure out the first node with the prefix + var first = bisect(-1); + var last = (first == -1 ? -1 : bisect(1)); + + if (first == -1) + { + table.className = ""; + status.innerHTML = "No results found, displaying all"; + } + else if (first == 0 && last == children.length - 1) + { + table.className = ""; + status.innerHTML = ""; + } + else if (last - first >= max_results && !full) + { + table.className = ""; + status.innerHTML = "More than " + max_results + ", press Search to display"; + } + else + { + // decide what you need to clear/show + if (shown_range) + setclass(shown_range[0], shown_range[1], "indexrow"); + setclass(first, last, "indexshow"); + shown_range = [first, last]; + table.className = "indexsearch"; + status.innerHTML = ""; + } + + + function setclass(first, last, status) + { + for (var i = first; i <= last; i++) + { + children[i].className = status; + } + } + + + // do a binary search, treating 0 as ... + // return either -1 (no 0's found) or location of most far match + function bisect(dir) + { + var first = 0, finish = children.length - 1; + var mid, success = false; + + while (finish - first > 3) + { + mid = Math.floor((finish + first) / 2); + + var i = checkitem(mid); + if (i == 0) i = dir; + if (i == -1) + finish = mid; + else + first = mid; + } + var a = (dir == 1 ? first : finish); + var b = (dir == 1 ? finish : first); + for (var i = b; i != a - dir; i -= dir) + { + if (checkitem(i) == 0) return i; + } + return -1; + } + + + // from an index, decide what the result is + // 0 = match, -1 is lower, 1 is higher + function checkitem(i) + { + var s = getitem(i).toLowerCase().substr(0, text.length); + if (s == text) return 0; + else return (s > text ? -1 : 1); + } + + + // from an index, get its string + // this abstracts over alternates + function getitem(i) + { + for ( ; i >= 0; i--) + { + var s = children[i].firstChild.firstChild.data; + if (s.indexOf(' ') == -1) + return s; + } + return ""; // should never be reached + } +} + +function setSynopsis(filename) { + if (parent.window.synopsis && parent.window.synopsis.location) { + if (parent.window.synopsis.location.replace) { + // In Firefox this avoids adding the change to the history. + parent.window.synopsis.location.replace(filename); + } else { + parent.window.synopsis.location = filename; + } + } +} + +function addMenuItem(html) { + var menu = document.getElementById("page-menu"); + if (menu) { + var btn = menu.firstChild.cloneNode(false); + btn.innerHTML = html; + menu.appendChild(btn); + } +} + +function adjustForFrames() { + var bodyCls; + + if (parent.location.href == window.location.href) { + // not in frames, so add Frames button + addMenuItem("Frames"); + bodyCls = "no-frame"; + } + else { + bodyCls = "in-frame"; + } + addClass(document.body, bodyCls); +} + +function reframe() { + setCookie("haddock-reframe", document.URL); + window.location = "frames.html"; +} + +function postReframe() { + var s = getCookie("haddock-reframe"); + if (s) { + parent.window.main.location = s; + clearCookie("haddock-reframe"); + } +} + +function styles() { + var i, a, es = document.getElementsByTagName("link"), rs = []; + for (i = 0; a = es[i]; i++) { + if(a.rel.indexOf("style") != -1 && a.title) { + rs.push(a); + } + } + return rs; +} + +function addStyleMenu() { + var as = styles(); + var i, a, btns = ""; + for(i=0; a = as[i]; i++) { + btns += "
  • " + + a.title + "
  • " + } + if (as.length > 1) { + var h = "
    " + + "Style ▾" + + "" + + "
    "; + addMenuItem(h); + } +} + +function setActiveStyleSheet(title) { + var as = styles(); + var i, a, found; + for(i=0; a = as[i]; i++) { + a.disabled = true; + // need to do this always, some browsers are edge triggered + if(a.title == title) { + found = a; + } + } + if (found) { + found.disabled = false; + setCookie("haddock-style", title); + } + else { + as[0].disabled = false; + clearCookie("haddock-style"); + } + styleMenu(false); +} + +function resetStyle() { + var s = getCookie("haddock-style"); + if (s) setActiveStyleSheet(s); +} + + +function styleMenu(show) { + var m = document.getElementById('style-menu'); + if (m) toggleShow(m, show); +} + + +function pageLoad() { + addStyleMenu(); + adjustForFrames(); + resetStyle(); + restoreCollapsed(); +} + diff --git a/hsfm.haddock b/hsfm.haddock new file mode 100644 index 0000000000000000000000000000000000000000..9c4b758c675ec13c69a881d2ea8ff0949cf33941 GIT binary patch literal 46155 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�jWRb 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 literal 0 HcmV?d00001 diff --git a/hslogo-16.png b/hslogo-16.png new file mode 100644 index 0000000000000000000000000000000000000000..0ff8579fbd897417b0d6dad6e920f8882138a7c0 GIT binary patch literal 1684 zcmV;F25b3=P)4Tx0C)j~RL^S@K@|QrZmG~B2wH0nvUrdpNm;9CMbtL^5n^i$+aIn^?(HA4aZWV5ov6ELTdbo0FI&wK{O>*+w4vx20?>!`FrQsdJlnHR>OPy zcd~b_n$otK2Za4V;76L-DzNVtaSB-y0*E}{p()372;bw_^6ZZ}PI-92wGS&j#91PI zKs7DSe@(bk%_Y-7gGe}(^>I=@oY#w#*Bu9GZf3^F5WP>3rn}7Ut74&?PWBFvy`A)a zPP5)V!Xd&78LdA?xQ(9mjMYElVd13a#D+Z_7&Y|xU=_C-srWU*6kiZcC!$nw*)9$7 zn6CX+@=AhmkT}X@VSsa5NKe;HZuq)~1$`#h6R+ZTR#D-3j}vF!)ZOnz+5)dI4jl{{ z44Mr{P!L4~VVJN`K!!XTF*LGrKO?IK8z<8w`3e3jI8lUGNUta*C8 zn(P`s>{pjD=7Kek#B;Fw@hxAK%$F&Q6vg9J^Xf~4by_hu-=A!MJ3Znq&n~srbFGPs zH&&aMXZ>nO`|hf|ljc?VPhR!${AbO?W8x_>CU%PFA&Hm8F7cAsOREdwU~R_;ot1_u z(ruCYB-LPGn!NQdT|ZlRy+(fw^-+`=%+gee_kY4FWHg<*4sZI8+sFJD270UUORdLHO0nA4V) z%{fwsET5CQ>B?eK%uw4yQc~9?*JVo2}ze(;aRcp*ceL#HUJSllrgm5wQKR zQu+C;QrUh^8rFfA`ftFz{YAidi-`aL010qNS#tmY4c7nw4c7reD4Tcy00T@(L_t(I z5sj2vNEA^R$7gqDc6T=2^@fUA2(c`MltuL5<|KW>RWz$&YbU@|M|{$E*8Tu-Ux!w z1Y*Dr&Ubfr&v-nZaaB{3ilRumrjPmk{sZvQEWlW+{o~IH|8)=s6c#X9S5s5d%J z4@)&QH5|xQY-)^L1n0pTRu0Lx9`08YTjTwn^6 z0;b1+aQ@)n;Em$q;=7BBi)v0zj&o^g>0Whp^_^5IbxIUP8C@y9;R?*Ouu}rmfxbU= zwtWVNke-m!=`7bYEhWpcI5#)9qp`8E0lr6IQ)ARL3Ui}Af@grj8aN1=r>Cb+prlzO zNfJs*N_tUm2ZL%5* zPmL2??da$TR904gL(VDAQ-Fv_Dk}Pdw*4T(%*f4MKLRg=4ekMjhe2mW zMFsBwg%ftWT}0kxRaIk1k7qJ8*#cKB;Ft{i`zVIs-Nqge;!!Ld7#O&Qqu7e0sJmP) z$MW*>L$vSB&dxp@iA3U9fo)-7!Czlr{|o7Hv{1oyg3xsu%gn@(b1>$;SM-ZaQ`HV=V0s;lr%d8bd;xY zGwNvm3=Iu=tyXIgtJnf@A(2S@M140N ew{UA~tMxaJq;$xaSSi*30000hsfm-gtk \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..be35506 --- /dev/null +++ b/index.html @@ -0,0 +1,4 @@ +hsfm-gtk \ No newline at end of file diff --git a/mini_HSFM-FileSystem-FileType.html b/mini_HSFM-FileSystem-FileType.html new file mode 100644 index 0000000..0497a3c --- /dev/null +++ b/mini_HSFM-FileSystem-FileType.html @@ -0,0 +1,4 @@ +HSFM.FileSystem.FileType

    HSFM.FileSystem.FileType

    \ No newline at end of file diff --git a/mini_HSFM-FileSystem-UtilTypes.html b/mini_HSFM-FileSystem-UtilTypes.html new file mode 100644 index 0000000..84c46c1 --- /dev/null +++ b/mini_HSFM-FileSystem-UtilTypes.html @@ -0,0 +1,4 @@ +HSFM.FileSystem.UtilTypes

    HSFM.FileSystem.UtilTypes

    \ No newline at end of file diff --git a/mini_HSFM-GUI-Glib-GlibString.html b/mini_HSFM-GUI-Glib-GlibString.html new file mode 100644 index 0000000..a2b8ef0 --- /dev/null +++ b/mini_HSFM-GUI-Glib-GlibString.html @@ -0,0 +1,4 @@ +HSFM.GUI.Glib.GlibString

    HSFM.GUI.Glib.GlibString

    \ No newline at end of file diff --git a/mini_HSFM-GUI-Gtk-Callbacks-Utils.html b/mini_HSFM-GUI-Gtk-Callbacks-Utils.html new file mode 100644 index 0000000..65bf859 --- /dev/null +++ b/mini_HSFM-GUI-Gtk-Callbacks-Utils.html @@ -0,0 +1,4 @@ +HSFM.GUI.Gtk.Callbacks.Utils

    HSFM.GUI.Gtk.Callbacks.Utils

    \ No newline at end of file diff --git a/mini_HSFM-GUI-Gtk-Callbacks.html b/mini_HSFM-GUI-Gtk-Callbacks.html new file mode 100644 index 0000000..41cf993 --- /dev/null +++ b/mini_HSFM-GUI-Gtk-Callbacks.html @@ -0,0 +1,4 @@ +HSFM.GUI.Gtk.Callbacks

    HSFM.GUI.Gtk.Callbacks

    \ No newline at end of file diff --git a/mini_HSFM-GUI-Gtk-Data.html b/mini_HSFM-GUI-Gtk-Data.html new file mode 100644 index 0000000..7dd0054 --- /dev/null +++ b/mini_HSFM-GUI-Gtk-Data.html @@ -0,0 +1,4 @@ +HSFM.GUI.Gtk.Data

    HSFM.GUI.Gtk.Data

    \ No newline at end of file diff --git a/mini_HSFM-GUI-Gtk-Dialogs.html b/mini_HSFM-GUI-Gtk-Dialogs.html new file mode 100644 index 0000000..9721e51 --- /dev/null +++ b/mini_HSFM-GUI-Gtk-Dialogs.html @@ -0,0 +1,4 @@ +HSFM.GUI.Gtk.Dialogs

    HSFM.GUI.Gtk.Dialogs

    \ No newline at end of file diff --git a/mini_HSFM-GUI-Gtk-Errors.html b/mini_HSFM-GUI-Gtk-Errors.html new file mode 100644 index 0000000..ec3eb12 --- /dev/null +++ b/mini_HSFM-GUI-Gtk-Errors.html @@ -0,0 +1,4 @@ +HSFM.GUI.Gtk.Errors

    HSFM.GUI.Gtk.Errors

    \ No newline at end of file diff --git a/mini_HSFM-GUI-Gtk-Icons.html b/mini_HSFM-GUI-Gtk-Icons.html new file mode 100644 index 0000000..6ac828f --- /dev/null +++ b/mini_HSFM-GUI-Gtk-Icons.html @@ -0,0 +1,4 @@ +HSFM.GUI.Gtk.Icons

    HSFM.GUI.Gtk.Icons

    \ No newline at end of file diff --git a/mini_HSFM-GUI-Gtk-MyGUI.html b/mini_HSFM-GUI-Gtk-MyGUI.html new file mode 100644 index 0000000..26915a8 --- /dev/null +++ b/mini_HSFM-GUI-Gtk-MyGUI.html @@ -0,0 +1,4 @@ +HSFM.GUI.Gtk.MyGUI

    HSFM.GUI.Gtk.MyGUI

    \ No newline at end of file diff --git a/mini_HSFM-GUI-Gtk-MyView.html b/mini_HSFM-GUI-Gtk-MyView.html new file mode 100644 index 0000000..d8fcfe6 --- /dev/null +++ b/mini_HSFM-GUI-Gtk-MyView.html @@ -0,0 +1,4 @@ +HSFM.GUI.Gtk.MyView

    HSFM.GUI.Gtk.MyView

    \ No newline at end of file diff --git a/mini_HSFM-GUI-Gtk-Utils.html b/mini_HSFM-GUI-Gtk-Utils.html new file mode 100644 index 0000000..c2800ea --- /dev/null +++ b/mini_HSFM-GUI-Gtk-Utils.html @@ -0,0 +1,4 @@ +HSFM.GUI.Gtk.Utils

    HSFM.GUI.Gtk.Utils

    \ No newline at end of file diff --git a/mini_HSFM-Utils-IO.html b/mini_HSFM-Utils-IO.html new file mode 100644 index 0000000..24d67e2 --- /dev/null +++ b/mini_HSFM-Utils-IO.html @@ -0,0 +1,4 @@ +HSFM.Utils.IO

    HSFM.Utils.IO

    \ No newline at end of file diff --git a/mini_HSFM-Utils-MyPrelude.html b/mini_HSFM-Utils-MyPrelude.html new file mode 100644 index 0000000..c04642c --- /dev/null +++ b/mini_HSFM-Utils-MyPrelude.html @@ -0,0 +1,4 @@ +HSFM.Utils.MyPrelude

    HSFM.Utils.MyPrelude

    \ No newline at end of file diff --git a/mini_Main.html b/mini_Main.html new file mode 100644 index 0000000..ad267a4 --- /dev/null +++ b/mini_Main.html @@ -0,0 +1,4 @@ +Main

    Main

    \ No newline at end of file diff --git a/mini_Paths_hsfm.html b/mini_Paths_hsfm.html new file mode 100644 index 0000000..c1b3ef7 --- /dev/null +++ b/mini_Paths_hsfm.html @@ -0,0 +1,4 @@ +Paths_hsfm

    Paths_hsfm

    \ No newline at end of file diff --git a/minus.gif b/minus.gif new file mode 100644 index 0000000000000000000000000000000000000000..1deac2fe1a42e35b994f1b855488f392c50f6a89 GIT binary patch literal 56 zcmZ?wbhEHb .doc { + display: table-cell; + padding-left: 0.5em; + margin-bottom: 0.5em; +} + +.subs ul li > .doc p { + margin: 0; +} + +/* Render short-style data instances */ +.inst ul { + height: 100%; + padding: 0.5em; + margin: 0; +} + +.inst, .inst li { + list-style: none; + margin-left: 1em; +} + +/* Workaround for bug in Firefox (issue #384) */ +.inst-left { + float: left; +} + +.top p.src { + border-top: 1px solid #ccc; +} + +.subs, .doc { + /* use this selector for one level of indent */ + padding-left: 2em; +} + +.warning { + color: red; +} + +.arguments { + margin-top: -0.4em; +} +.arguments .caption { + display: none; +} + +.fields { padding-left: 1em; } + +.fields .caption { display: none; } + +.fields p { margin: 0 0; } + +/* this seems bulky to me +.methods, .constructors { + background: #f8f8f8; + border: 1px solid #eee; +} +*/ + +/* @end */ + +/* @group Auxillary Pages */ + + +.extension-list { + list-style-type: none; + margin-left: 0; +} + +#mini { + margin: 0 auto; + padding: 0 1em 1em; +} + +#mini > * { + font-size: 93%; /* 12pt */ +} + +#mini #module-list .caption, +#mini #module-header .caption { + font-size: 125%; /* 15pt */ +} + +#mini #interface h1, +#mini #interface h2, +#mini #interface h3, +#mini #interface h4 { + font-size: 109%; /* 13pt */ + margin: 1em 0 0; +} + +#mini #interface .top, +#mini #interface .src { + margin: 0; +} + +#mini #module-list ul { + list-style: none; + margin: 0; +} + +#alphabet ul { + list-style: none; + padding: 0; + margin: 0.5em 0 0; + text-align: center; +} + +#alphabet li { + display: inline; + margin: 0 0.25em; +} + +#alphabet a { + font-weight: bold; +} + +#index .caption, +#module-list .caption { font-size: 131%; /* 17pt */ } + +#index table { + margin-left: 2em; +} + +#index .src { + font-weight: bold; +} +#index .alt { + font-size: 77%; /* 10pt */ + font-style: italic; + padding-left: 2em; +} + +#index td + td { + padding-left: 1em; +} + +#module-list ul { + list-style: none; + margin: 0 0 0 2em; +} + +#module-list li { + clear: right; +} + +#module-list span.collapser, +#module-list span.expander { + background-position: 0 0.3em; +} + +#module-list .package { + float: right; +} + +/* @end */ diff --git a/plus.gif b/plus.gif new file mode 100644 index 0000000000000000000000000000000000000000..2d15c14173d23f664b955cd24f51c82f5f09d91d GIT binary patch literal 59 zcmZ?wbhEHbgbBX M^XE!9f*2UA0nx1yDgXcg literal 0 HcmV?d00001 diff --git a/src/HSFM-GUI-Glib-GlibString.html b/src/HSFM-GUI-Glib-GlibString.html new file mode 100644 index 0000000..ca19cda --- /dev/null +++ b/src/HSFM-GUI-Glib-GlibString.html @@ -0,0 +1,91 @@ + + + + + +src/HSFM/GUI/Glib/GlibString.hs + + + +
    {--
    +HSFM, a filemanager written in Haskell.
    +Copyright (C) 2016 Julian Ospald
    +
    +This program is free software; you can redistribute it and/or
    +modify it under the terms of the GNU General Public License
    +version 2 as published by the Free Software Foundation.
    +
    +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.
    +
    +You should have received a copy of the GNU General Public License
    +along with this program; if not, write to the Free Software
    +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    +--}
    +
    +{-# LANGUAGE OverloadedStrings #-}
    +{-# OPTIONS_HADDOCK ignore-exports #-}
    +
    +
    +module HSFM.GUI.Glib.GlibString where
    +
    +
    +import qualified Data.ByteString as BS
    +import Data.ByteString.UTF8
    +  (
    +    toString
    +  )
    +import Data.Word8
    +  (
    +    _percent
    +  )
    +import Foreign.C.String
    +  (
    +    CStringLen
    +  , CString
    +  )
    +import Foreign.C.Types
    +  (
    +    CSize(..)
    +  )
    +import Foreign.Marshal.Utils
    +  (
    +    maybePeek
    +  )
    +import Foreign.Ptr
    +  (
    +    nullPtr
    +  , plusPtr
    +  )
    +import System.Glib.UTFString
    +
    +
    +
    +-- TODO: move this to its own module
    +instance GlibString BS.ByteString where
    +    withUTFString = BS.useAsCString
    +    withUTFStringLen s f = BS.useAsCStringLen  s (f . noNullPtrs)
    +    peekUTFString s = do
    +        len <- c_strlen s
    +        BS.packCStringLen (s, fromIntegral len)
    +    maybePeekUTFString = maybePeek peekUTFString
    +    peekUTFStringLen = BS.packCStringLen
    +    newUTFString = newUTFString . toString
    +    newUTFStringLen = newUTFStringLen . toString
    +    genUTFOfs = genUTFOfs . toString
    +    stringLength = BS.length
    +    unPrintf s = BS.intercalate "%%" (BS.split _percent s)
    +
    +
    +foreign import ccall unsafe "string.h strlen" c_strlen
    +    :: CString -> IO CSize
    +
    +
    +noNullPtrs :: CStringLen -> CStringLen
    +noNullPtrs (p, 0) | p == nullPtr = (plusPtr p 1, 0)
    +noNullPtrs s = s
    +
    +
    + diff --git a/src/HSFM-GUI-Gtk-Callbacks-Utils.html b/src/HSFM-GUI-Gtk-Callbacks-Utils.html new file mode 100644 index 0000000..8dc64df --- /dev/null +++ b/src/HSFM-GUI-Gtk-Callbacks-Utils.html @@ -0,0 +1,121 @@ + + + + + +src/HSFM/GUI/Gtk/Callbacks/Utils.hs + + + +
    {--
    +HSFM, a filemanager written in Haskell.
    +Copyright (C) 2016 Julian Ospald
    +
    +This program is free software; you can redistribute it and/or
    +modify it under the terms of the GNU General Public License
    +version 2 as published by the Free Software Foundation.
    +
    +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.
    +
    +You should have received a copy of the GNU General Public License
    +along with this program; if not, write to the Free Software
    +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    +--}
    +
    +{-# LANGUAGE OverloadedStrings #-}
    +{-# LANGUAGE ScopedTypeVariables #-}
    +{-# OPTIONS_HADDOCK ignore-exports #-}
    +
    +module HSFM.GUI.Gtk.Callbacks.Utils where
    +
    +
    +
    +import Control.Monad
    +  (
    +    forM
    +  , forM_
    +  )
    +import Control.Monad.IO.Class
    +  (
    +    liftIO
    +  )
    +import GHC.IO.Exception
    +  (
    +    IOErrorType(..)
    +  )
    +import Graphics.UI.Gtk
    +import qualified HPath as P
    +import HPath.IO
    +import HPath.IO.Errors
    +import HSFM.FileSystem.FileType
    +import HSFM.FileSystem.UtilTypes
    +import HSFM.GUI.Gtk.Data
    +import HSFM.GUI.Gtk.Dialogs
    +import HSFM.GUI.Gtk.MyView
    +import HSFM.GUI.Gtk.Utils
    +import HSFM.Utils.IO
    +  (
    +    modifyTVarIO
    +  )
    +import Prelude hiding(readFile)
    +import Control.Concurrent.STM.TVar
    +  (
    +    readTVarIO
    +  )
    +
    +
    +
    +
    +-- |Carries out a file operation with the appropriate error handling
    +-- allowing the user to react to various exceptions with further input.
    +doFileOperation :: FileOperation -> IO ()
    +doFileOperation (FCopy (Copy (f':fs') to)) =
    +  _doFileOperation (f':fs') to easyCopyOverwrite easyCopy
    +    $ doFileOperation (FCopy $ Copy fs' to)
    +doFileOperation (FMove (Move (f':fs') to)) =
    +  _doFileOperation (f':fs') to moveFileOverwrite moveFile
    +    $ doFileOperation (FMove $ Move fs' to)
    +doFileOperation _ = return ()
    +
    +
    +_doFileOperation :: [P.Path b1]
    +                 -> P.Path P.Abs
    +                 -> (P.Path b1 -> P.Path P.Abs -> IO b)
    +                 -> (P.Path b1 -> P.Path P.Abs -> IO a)
    +                 -> IO ()
    +                 -> IO ()
    +_doFileOperation [] _ _ _ _ = return ()
    +_doFileOperation (f:fs) to mcOverwrite mc rest = do
    +  toname <- P.basename f
    +  let topath = to P.</> toname
    +  reactOnError (mc f topath >> rest)
    +    [(AlreadyExists  , collisionAction fileCollisionDialog topath)]
    +    [(FileDoesExist{}, collisionAction fileCollisionDialog topath)
    +    ,(DirDoesExist{} , collisionAction fileCollisionDialog topath)
    +    ,(SameFile{}     , collisionAction renameDialog topath)]
    +  where
    +    collisionAction diag topath = do
    +      mcm <- diag . P.fromAbs $ topath
    +      forM_ mcm $ \cm -> case cm of
    +        Overwrite    -> mcOverwrite f topath >> rest
    +        OverwriteAll -> forM_ (f:fs) $ \x -> do
    +                          toname' <- P.basename x
    +                          mcOverwrite x (to P.</> toname')
    +        Skip         -> rest
    +        Rename newn  -> mc f (to P.</> newn) >> rest
    +        _            -> return ()
    +
    +
    +-- |Helper that is invoked for any directory change operations.
    +goDir :: MyGUI -> MyView -> Item -> IO ()
    +goDir mygui myview item = do
    +  cdir <- getCurrentDir myview
    +  modifyTVarIO (history myview)
    +    (\(p, _) -> (path cdir `addHistory` p, []))
    +  refreshView' mygui myview item
    +
    +
    + diff --git a/src/HSFM-GUI-Gtk-Callbacks.html b/src/HSFM-GUI-Gtk-Callbacks.html new file mode 100644 index 0000000..2363dfb --- /dev/null +++ b/src/HSFM-GUI-Gtk-Callbacks.html @@ -0,0 +1,554 @@ + + + + + +src/HSFM/GUI/Gtk/Callbacks.hs + + + +
    {--
    +HSFM, a filemanager written in Haskell.
    +Copyright (C) 2016 Julian Ospald
    +
    +This program is free software; you can redistribute it and/or
    +modify it under the terms of the GNU General Public License
    +version 2 as published by the Free Software Foundation.
    +
    +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.
    +
    +You should have received a copy of the GNU General Public License
    +along with this program; if not, write to the Free Software
    +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    +--}
    +
    +{-# LANGUAGE OverloadedStrings #-}
    +{-# OPTIONS_HADDOCK ignore-exports #-}
    +
    +module HSFM.GUI.Gtk.Callbacks where
    +
    +
    +import Control.Applicative
    +  (
    +    (<$>)
    +  )
    +import Control.Concurrent.STM
    +  (
    +    readTVarIO
    +  )
    +import Control.Exception
    +  (
    +    throwIO
    +  )
    +import Control.Monad
    +  (
    +    forM_
    +  , void
    +  , when
    +  )
    +import Control.Monad.IO.Class
    +  (
    +    liftIO
    +  )
    +import Data.ByteString
    +  (
    +    ByteString
    +  )
    +import Data.ByteString.UTF8
    +  (
    +    fromString
    +  , toString
    +  )
    +import Data.Foldable
    +  (
    +    for_
    +  )
    +import Graphics.UI.Gtk
    +import qualified HPath as P
    +import HPath
    +    (
    +      Abs
    +    , Path
    +    )
    +import HPath.IO
    +import HPath.IO.Errors
    +import HPath.IO.Utils
    +import HSFM.FileSystem.FileType
    +import HSFM.FileSystem.UtilTypes
    +import HSFM.GUI.Gtk.Callbacks.Utils
    +import HSFM.GUI.Gtk.Data
    +import HSFM.GUI.Gtk.Dialogs
    +import HSFM.GUI.Gtk.MyView
    +import HSFM.GUI.Gtk.Utils
    +import HSFM.Utils.IO
    +import Prelude hiding(readFile)
    +import System.Glib.UTFString
    +  (
    +    glibToString
    +  )
    +import System.Posix.Env.ByteString
    +  (
    +    getEnv
    +  )
    +import qualified System.Posix.Process.ByteString as SPP
    +import System.Posix.Types
    +  (
    +    ProcessID
    +  )
    +
    +
    +
    +
    +
    +    -----------------
    +    --[ Callbacks ]--
    +    -----------------
    +
    +
    +
    +
    +---- MAIN CALLBACK ENTRYPOINT ----
    +
    +
    +-- |Set callbacks for the whole gui, on hotkeys, events and stuff.
    +setGUICallbacks :: MyGUI -> IO ()
    +setGUICallbacks mygui = do
    +
    +  _ <- clearStatusBar mygui `on` buttonActivated $ do
    +       popStatusbar mygui
    +       writeTVarIO (operationBuffer mygui) None
    +
    +  -- menubar-file
    +  _ <- (menubarFileQuit . menubar) mygui `on` menuItemActivated $
    +    mainQuit
    +
    +  -- menubar-help
    +  _ <- (menubarHelpAbout . menubar) mygui `on` menuItemActivated $
    +    liftIO showAboutDialog
    +  return ()
    +
    +  -- key events
    +  _ <- rootWin mygui `on` keyPressEvent $ tryEvent $ do
    +    [Control] <- eventModifier
    +    "q"       <- fmap glibToString eventKeyName
    +    liftIO mainQuit
    +
    +  return ()
    +
    +
    +-- |Set callbacks specific to a given view, on hotkeys, events and stuff.
    +setViewCallbacks :: MyGUI -> MyView -> IO ()
    +setViewCallbacks mygui myview = do
    +  view' <- readTVarIO $ view myview
    +  case view' of
    +    fmv@(FMTreeView treeView) -> do
    +      _ <- treeView `on` rowActivated
    +             $ (\_ _ -> withItems mygui myview open)
    +
    +      -- drag events
    +      _ <- treeView `on` dragBegin $
    +        \_ -> withItems mygui myview moveInit
    +      _ <- treeView `on` dragDrop $
    +         \dc p ts -> do
    +           p'    <- treeViewConvertWidgetToTreeCoords treeView p
    +           mpath <- treeViewGetPathAtPos treeView p'
    +           case mpath of
    +             Nothing -> do
    +               dragFinish dc False False ts
    +               return False
    +             Just _  -> do
    +               atom  <- atomNew ("HSFM" :: String)
    +               dragGetData treeView dc atom ts
    +               return True
    +      _ <- treeView `on` dragDataReceived $
    +        \dc p _ ts ->
    +          liftIO $ do
    +            signalStopEmission treeView "drag_data_received"
    +            p'    <- treeViewConvertWidgetToTreeCoords treeView p
    +            mpath <- treeViewGetPathAtPos treeView p'
    +            case mpath of
    +              Nothing         -> dragFinish dc False False ts
    +              Just (tp, _, _) -> do
    +                mitem <- rawPathToItem myview tp
    +                forM_ mitem $ \item ->
    +                  operationFinal mygui myview (Just item)
    +                dragFinish dc True False ts
    +
    +      commonGuiEvents fmv
    +      return ()
    +    fmv@(FMIconView iconView) -> do
    +      _ <- iconView `on` itemActivated
    +             $ (\_ -> withItems mygui myview open)
    +      commonGuiEvents fmv
    +      return ()
    +  where
    +    commonGuiEvents fmv = do
    +      let view = fmViewToContainer fmv
    +
    +      -- GUI events
    +      _ <- urlBar myview `on` entryActivated $ urlGoTo mygui myview
    +      _ <- upViewB myview `on` buttonActivated $
    +           upDir mygui myview
    +      _ <- homeViewB myview `on` buttonActivated $
    +           goHome mygui myview
    +      _ <- refreshViewB myview `on` buttonActivated $ do
    +           cdir <- liftIO $ getCurrentDir myview
    +           refreshView' mygui myview cdir
    +
    +      -- key events
    +      _ <- viewBox myview `on` keyPressEvent $ tryEvent $ do
    +        [Control] <- eventModifier
    +        "h"       <- fmap glibToString eventKeyName
    +        cdir <- liftIO $ getCurrentDir myview
    +        liftIO $ modifyTVarIO (settings mygui)
    +                              (\x -> x { showHidden = not . showHidden $ x})
    +                 >> refreshView' mygui myview cdir
    +      _ <- viewBox myview `on` keyPressEvent $ tryEvent $ do
    +        [Alt] <- eventModifier
    +        "Up"  <- fmap glibToString eventKeyName
    +        liftIO $ upDir mygui myview
    +      _ <- viewBox myview `on` keyPressEvent $ tryEvent $ do
    +        [Alt] <- eventModifier
    +        "Left"  <- fmap glibToString eventKeyName
    +        liftIO $ goHistoryPrev mygui myview
    +      _ <- viewBox myview `on` keyPressEvent $ tryEvent $ do
    +        [Alt] <- eventModifier
    +        "Right"  <- fmap glibToString eventKeyName
    +        liftIO $ goHistoryNext mygui myview
    +      _ <- view `on` keyPressEvent $ tryEvent $ do
    +        "Delete"  <- fmap glibToString eventKeyName
    +        liftIO $ withItems mygui myview del
    +      _ <- view `on` keyPressEvent $ tryEvent $ do
    +        []            <- eventModifier
    +        "Return"      <- fmap glibToString eventKeyName
    +        liftIO $ withItems mygui myview open
    +      _ <- view `on` keyPressEvent $ tryEvent $ do
    +        [Control] <- eventModifier
    +        "c"       <- fmap glibToString eventKeyName
    +        liftIO $ withItems mygui myview copyInit
    +      _ <- view `on` keyPressEvent $ tryEvent $ do
    +        [Control] <- eventModifier
    +        "x"       <- fmap glibToString eventKeyName
    +        liftIO $ withItems mygui myview moveInit
    +      _ <- viewBox myview `on` keyPressEvent $ tryEvent $ do
    +        [Control] <- eventModifier
    +        "v"       <- fmap glibToString eventKeyName
    +        liftIO $ operationFinal mygui myview Nothing
    +      _ <- viewBox myview `on` keyPressEvent $ tryEvent $ do
    +        [Control] <- eventModifier
    +        "t"       <- fmap glibToString eventKeyName
    +        liftIO $ void $ do
    +          cwd <- getCurrentDir myview
    +          newTab mygui createTreeView (path cwd)
    +      _ <- viewBox myview `on` keyPressEvent $ tryEvent $ do
    +        [Control] <- eventModifier
    +        "w"       <- fmap glibToString eventKeyName
    +        liftIO $ void $ closeTab mygui myview
    +      _ <- viewBox myview `on` keyPressEvent $ tryEvent $ do
    +        "F4"       <- fmap glibToString eventKeyName
    +        liftIO $ void $ openTerminalHere myview
    +
    +      -- righ-click
    +      _ <- view `on` buttonPressEvent $ do
    +        eb <- eventButton
    +        t  <- eventTime
    +        case eb of
    +          RightButton -> do
    +              _ <- liftIO $ menuPopup (rcMenu . rcmenu $ myview)
    +                          $ Just (RightButton, t)
    +              -- this is just to not screw with current selection
    +              -- on right-click
    +              -- TODO: this misbehaves under IconView
    +              (x, y) <- eventCoordinates
    +              mpath  <- liftIO $ getPathAtPos fmv (x, y)
    +              case mpath of
    +                -- item under the cursor, only pass on the signal
    +                -- if the item under the cursor is not within the current
    +                -- selection
    +                (Just tp) -> do
    +                  selectedTps <- liftIO $ getSelectedTreePaths mygui myview
    +                  return $ elem tp selectedTps
    +                -- no item under the cursor, pass on the signal
    +                Nothing -> return False
    +          MiddleButton -> do
    +            liftIO $ goHistoryPrev mygui myview
    +            return False
    +          OtherButton 8 -> do
    +            liftIO $ goHistoryPrev mygui myview
    +            return False
    +          OtherButton 9 -> do
    +            liftIO $ goHistoryNext mygui myview
    +            return False
    +          -- not right-click, so pass on the signal
    +          _ -> return False
    +
    +      -- right click menu
    +      _ <- (rcFileOpen . rcmenu) myview `on` menuItemActivated $
    +        liftIO $ withItems mygui myview open
    +      _ <- (rcFileExecute . rcmenu) myview `on` menuItemActivated $
    +        liftIO $ withItems mygui myview execute
    +      _ <- (rcFileNewRegFile . rcmenu) myview `on` menuItemActivated $
    +        liftIO $ newFile mygui myview
    +      _ <- (rcFileNewDir . rcmenu) myview `on` menuItemActivated $
    +        liftIO $ newDir mygui myview
    +      _ <- (rcFileCopy . rcmenu) myview `on` menuItemActivated $
    +        liftIO $ withItems mygui myview copyInit
    +      _ <- (rcFileRename . rcmenu) myview `on` menuItemActivated $
    +        liftIO $ withItems mygui myview renameF
    +      _ <- (rcFilePaste . rcmenu) myview `on` menuItemActivated $
    +        liftIO $ operationFinal mygui myview Nothing
    +      _ <- (rcFileDelete . rcmenu) myview `on` menuItemActivated $
    +        liftIO $ withItems mygui myview del
    +      _ <- (rcFileProperty . rcmenu) myview `on` menuItemActivated $
    +        liftIO $ withItems mygui myview showFilePropertyDialog
    +      _ <- (rcFileCut . rcmenu) myview `on` menuItemActivated $
    +        liftIO $ withItems mygui myview moveInit
    +      _ <- (rcFileIconView . rcmenu) myview `on` menuItemActivated $
    +        liftIO $ switchView mygui myview createIconView
    +      _ <- (rcFileTreeView . rcmenu) myview `on` menuItemActivated $
    +        liftIO $ switchView mygui myview createTreeView
    +      return ()
    +
    +    getPathAtPos fmv (x, y) =
    +      case fmv of
    +        FMTreeView treeView -> do
    +          mp <- treeViewGetPathAtPos treeView (round x, round y)
    +          return $ fmap (\(p, _, _) -> p) mp
    +        FMIconView iconView ->
    +           fmap (\tp -> if null tp then Nothing else Just tp)
    +                  $ iconViewGetPathAtPos iconView (round x) (round y)
    +
    +
    +
    +
    +---- OTHER ----
    +
    +
    +openTerminalHere :: MyView -> IO ProcessID
    +openTerminalHere myview = do
    +  cwd <- (P.fromAbs . path) <$> getCurrentDir myview
    +  -- TODO: make terminal configurable
    +  SPP.forkProcess $ SPP.executeFile "sakura" True ["-d", cwd] Nothing
    +
    +
    +
    +
    +---- TAB OPERATIONS ----
    +
    +
    +-- |Closes the current tab, but only if there is more than one tab.
    +closeTab :: MyGUI -> MyView -> IO ()
    +closeTab mygui myview = do
    +  n <- notebookGetNPages (notebook mygui)
    +  when (n > 1) $ void $ destroyView mygui myview
    +
    +
    +newTabHere :: MyGUI -> MyView -> [Item] -> IO ()
    +newTabHere mygui myview [item] = undefined
    +newTabHere mygui myview _ = return ()
    +
    +
    +---- FILE OPERATION CALLBACKS (COPY, MOVE, ...) ----
    +
    +
    +-- |Supposed to be used with 'withRows'. Deletes a file or directory.
    +del :: [Item] -> MyGUI -> MyView -> IO ()
    +del [item] _ _ = withErrorDialog $ do
    +  let cmsg  = "Really delete \"" ++ getFPasStr item ++ "\"?"
    +  withConfirmationDialog cmsg
    +    $ easyDelete . path $ item
    +-- this throws on the first error that occurs
    +del items@(_:_) _ _ = withErrorDialog $ do
    +  let cmsg  = "Really delete " ++ show (length items) ++ " files?"
    +  withConfirmationDialog cmsg
    +    $ forM_ items $ \item -> easyDelete . path $ item
    +del _ _ _ = withErrorDialog
    +              . throwIO $ InvalidOperation
    +                          "Operation not supported on multiple files"
    +
    +
    +-- |Initializes a file move operation.
    +moveInit :: [Item] -> MyGUI -> MyView -> IO ()
    +moveInit items@(_:_) mygui _ = do
    +  writeTVarIO (operationBuffer mygui) (FMove . PartialMove . map path $ items)
    +  let sbmsg = case items of
    +              (item:[]) -> "Move buffer: " ++ getFPasStr item
    +              _         -> "Move buffer: " ++ (show . length $ items)
    +                                           ++ " items"
    +  popStatusbar mygui
    +  void $ pushStatusBar mygui sbmsg
    +moveInit _ _ _ = withErrorDialog
    +                   . throwIO $ InvalidOperation
    +                               "No file selected!"
    +
    +-- |Supposed to be used with 'withRows'. Initializes a file copy operation.
    +copyInit :: [Item] -> MyGUI -> MyView -> IO ()
    +copyInit items@(_:_) mygui _ = do
    +  writeTVarIO (operationBuffer mygui) (FCopy . PartialCopy . map path $ items)
    +  let sbmsg = case items of
    +              (item:[]) -> "Copy buffer: " ++ getFPasStr item
    +              _         -> "Copy buffer: " ++ (show . length $ items)
    +                                           ++ " items"
    +  popStatusbar mygui
    +  void $ pushStatusBar mygui sbmsg
    +copyInit _ _ _ = withErrorDialog
    +                   . throwIO $ InvalidOperation
    +                               "No file selected!"
    +
    +
    +-- |Finalizes a file operation, such as copy or move.
    +operationFinal :: MyGUI -> MyView -> Maybe Item -> IO ()
    +operationFinal mygui myview mitem = withErrorDialog $ do
    +  op <- readTVarIO (operationBuffer mygui)
    +  cdir <- case mitem of
    +            Nothing -> path <$> getCurrentDir myview
    +            Just x  -> return $ path x
    +  case op of
    +    FMove (PartialMove s) -> do
    +      let cmsg = "Really move " ++ imsg s
    +                  ++ " to \"" ++ toString (P.fromAbs cdir)
    +                  ++ "\"?"
    +      withConfirmationDialog cmsg $ doFileOperation (FMove $ Move s cdir)
    +      popStatusbar mygui
    +      writeTVarIO (operationBuffer mygui) None
    +    FCopy (PartialCopy s) -> do
    +      let cmsg = "Really copy " ++ imsg s
    +                 ++ " to \"" ++ toString (P.fromAbs cdir)
    +                 ++ "\"?"
    +      withConfirmationDialog cmsg $ doFileOperation (FCopy $ Copy s cdir)
    +    _ -> return ()
    +  where
    +    imsg s = case s of
    +               (item:[]) -> "\"" ++ toString (P.fromAbs item) ++ "\""
    +               items     -> (show . length $ items) ++ " items"
    +
    +
    +-- |Create a new file.
    +newFile :: MyGUI -> MyView -> IO ()
    +newFile _ myview = withErrorDialog $ do
    +  mfn   <- textInputDialog "Enter file name" ("" :: String)
    +  let pmfn = P.parseFn =<< fromString <$> mfn
    +  for_ pmfn $ \fn -> do
    +    cdir  <- getCurrentDir myview
    +    createRegularFile (path cdir P.</> fn)
    +
    +
    +-- |Create a new directory.
    +newDir :: MyGUI -> MyView -> IO ()
    +newDir _ myview = withErrorDialog $ do
    +  mfn   <- textInputDialog "Enter directory name" ("" :: String)
    +  let pmfn = P.parseFn =<< fromString <$> mfn
    +  for_ pmfn $ \fn -> do
    +    cdir  <- getCurrentDir myview
    +    createDir (path cdir P.</> fn)
    +
    +
    +renameF :: [Item] -> MyGUI -> MyView -> IO ()
    +renameF [item] _ _ = withErrorDialog $ do
    +  iname <- P.fromRel <$> (P.basename $ path item)
    +  mfn  <- textInputDialog "Enter new file name" (iname :: ByteString)
    +  let pmfn = P.parseFn =<< fromString <$> mfn
    +  for_ pmfn $ \fn -> do
    +    let cmsg = "Really rename \"" ++ getFPasStr item
    +               ++ "\"" ++ " to \""
    +               ++ toString (P.fromAbs $ (P.dirname . path $ item)
    +                                             P.</> fn) ++ "\"?"
    +    withConfirmationDialog cmsg $
    +      HPath.IO.renameFile (path item)
    +                          ((P.dirname $ path item) P.</> fn)
    +renameF _ _ _ = withErrorDialog
    +                  . throwIO $ InvalidOperation
    +                              "Operation not supported on multiple files"
    +
    +
    +
    +
    +---- DIRECTORY TRAVERSAL AND FILE OPENING CALLBACKS ----
    +
    +
    +-- |Go to the url given at the 'urlBar' and visualize it in the given
    +-- treeView.
    +--
    +-- If the url is invalid, does nothing.
    +urlGoTo :: MyGUI -> MyView -> IO ()
    +urlGoTo mygui myview = withErrorDialog $ do
    +  fp <- entryGetText (urlBar myview)
    +  forM_ (P.parseAbs fp :: Maybe (Path Abs)) $ \fp' ->
    +      whenM (canOpenDirectory fp')
    +            (goDir mygui myview =<< (readFile getFileInfo $ fp'))
    +
    +
    +goHome :: MyGUI -> MyView -> IO ()
    +goHome mygui myview =  withErrorDialog $ do
    +  mhomedir <- getEnv "HOME"
    +  forM_ (P.parseAbs =<< mhomedir :: Maybe (Path Abs)) $ \fp' ->
    +      whenM (canOpenDirectory fp')
    +            (goDir mygui myview =<< (readFile getFileInfo $ fp'))
    +
    +
    +-- |Execute a given file.
    +execute :: [Item] -> MyGUI -> MyView -> IO ()
    +execute [item] _ _ = withErrorDialog $
    +  void $ executeFile (path item) []
    +execute _ _ _ = withErrorDialog
    +                  . throwIO $ InvalidOperation
    +                              "Operation not supported on multiple files"
    +
    +
    +-- |Supposed to be used with 'withRows'. Opens a file or directory.
    +open :: [Item] -> MyGUI -> MyView -> IO ()
    +open [item] mygui myview = withErrorDialog $
    +  case item of
    +    DirOrSym r -> do
    +      nv <- readFile getFileInfo $ path r
    +      goDir mygui myview nv
    +    r ->
    +      void $ openFile . path $ r
    +-- this throws on the first error that occurs
    +open (FileLikeList fs) _ _ = withErrorDialog $
    +  forM_ fs $ \f -> void $ openFile . path $ f
    +open _ _ _ = withErrorDialog
    +               . throwIO $ InvalidOperation
    +                           "Operation not supported on multiple files"
    +
    +
    +-- |Go up one directory and visualize it in the treeView.
    +upDir :: MyGUI -> MyView -> IO ()
    +upDir mygui myview = withErrorDialog $ do
    +  cdir <- getCurrentDir myview
    +  nv <- goUp cdir
    +  goDir mygui myview nv
    +
    +
    +-- |Go "back" in the history.
    +goHistoryPrev :: MyGUI -> MyView -> IO ()
    +goHistoryPrev mygui myview = do
    +  hs <- readTVarIO (history myview)
    +  case hs of
    +    ([], _) -> return ()
    +    (x:xs, _) -> do
    +      cdir <- getCurrentDir myview
    +      nv <- readFile getFileInfo $ x
    +      modifyTVarIO (history myview)
    +        (\(_, n) -> (xs, path cdir `addHistory` n))
    +      refreshView' mygui myview nv
    +
    +
    +-- |Go "forth" in the history.
    +goHistoryNext :: MyGUI -> MyView -> IO ()
    +goHistoryNext mygui myview = do
    +  hs <- readTVarIO (history myview)
    +  case hs of
    +    (_, []) -> return ()
    +    (_, x:xs) -> do
    +      cdir <- getCurrentDir myview
    +      nv <- readFile getFileInfo $ x
    +      modifyTVarIO (history myview)
    +        (\(p, _) -> (path cdir `addHistory` p, xs))
    +      refreshView' mygui myview nv
    +
    +
    + diff --git a/src/HSFM-GUI-Gtk-Data.html b/src/HSFM-GUI-Gtk-Data.html new file mode 100644 index 0000000..4f11e33 --- /dev/null +++ b/src/HSFM-GUI-Gtk-Data.html @@ -0,0 +1,161 @@ + + + + + +src/HSFM/GUI/Gtk/Data.hs + + + +
    {--
    +HSFM, a filemanager written in Haskell.
    +Copyright (C) 2016 Julian Ospald
    +
    +This program is free software; you can redistribute it and/or
    +modify it under the terms of the GNU General Public License
    +version 2 as published by the Free Software Foundation.
    +
    +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.
    +
    +You should have received a copy of the GNU General Public License
    +along with this program; if not, write to the Free Software
    +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    +--}
    +
    +{-# OPTIONS_HADDOCK ignore-exports #-}
    +
    +module HSFM.GUI.Gtk.Data where
    +
    +
    +import Control.Concurrent.MVar
    +  (
    +    MVar
    +  )
    +import Control.Concurrent.STM
    +  (
    +    TVar
    +  )
    +import Graphics.UI.Gtk hiding (MenuBar)
    +import HPath
    +  (
    +    Abs
    +  , Path
    +  )
    +import HSFM.FileSystem.FileType
    +import HSFM.FileSystem.UtilTypes
    +import System.INotify
    +  (
    +    INotify
    +  )
    +
    +
    +
    +    ------------------
    +    --[ Base Types ]--
    +    ------------------
    +
    +
    +-- |Monolithic object passed to various GUI functions in order
    +-- to keep the API stable and not alter the parameters too much.
    +-- This only holds GUI widgets that are needed to be read during
    +-- runtime.
    +data MyGUI = MkMyGUI {
    +  -- |main Window
    +    rootWin :: !Window
    +
    +  -- widgets on the main window
    +  , menubar        :: !MenuBar
    +  , statusBar      :: !Statusbar
    +  , clearStatusBar :: !Button
    +  , notebook       :: !Notebook
    +
    +  -- other
    +  , fprop    :: !FilePropertyGrid
    +  , settings :: !(TVar FMSettings)
    +
    +  , operationBuffer :: !(TVar FileOperation)
    +}
    +
    +
    +-- |This describes the contents of the current view and is separated from MyGUI,
    +-- because we might want to have multiple views.
    +data MyView = MkMyView {
    +    view            :: !(TVar FMView)
    +  , cwd             :: !(MVar Item)
    +  , rawModel        :: !(TVar (ListStore Item))
    +  , sortedModel     :: !(TVar (TypedTreeModelSort Item))
    +  , filteredModel   :: !(TVar (TypedTreeModelFilter Item))
    +  , inotify         :: !(MVar INotify)
    +
    +  -- the first part of the tuple represents the "go back"
    +  -- the second part the "go forth" in the history
    +  , history         :: !(TVar ([Path Abs], [Path Abs]))
    +
    +  -- sub-widgets
    +  , scroll       :: !ScrolledWindow
    +  , viewBox      :: !Box
    +  , rcmenu       :: !RightClickMenu
    +  , upViewB      :: !Button
    +  , homeViewB    :: !Button
    +  , refreshViewB :: !Button
    +  , urlBar       :: !Entry
    +}
    +
    +
    +data MenuBar = MkMenuBar {
    +    menubarFileQuit  :: !ImageMenuItem
    +  , menubarHelpAbout :: !ImageMenuItem
    +}
    +
    +data RightClickMenu = MkRightClickMenu {
    +    rcMenu           :: !Menu
    +  , rcFileOpen       :: !ImageMenuItem
    +  , rcFileExecute    :: !ImageMenuItem
    +  , rcFileNewRegFile :: !ImageMenuItem
    +  , rcFileNewDir     :: !ImageMenuItem
    +  , rcFileCut        :: !ImageMenuItem
    +  , rcFileCopy       :: !ImageMenuItem
    +  , rcFileRename     :: !ImageMenuItem
    +  , rcFilePaste      :: !ImageMenuItem
    +  , rcFileDelete     :: !ImageMenuItem
    +  , rcFileProperty   :: !ImageMenuItem
    +  , rcFileIconView   :: !ImageMenuItem
    +  , rcFileTreeView   :: !ImageMenuItem
    +}
    +
    +data FilePropertyGrid = MkFilePropertyGrid {
    +    fpropGrid      :: !Grid
    +  , fpropFnEntry   :: !Entry
    +  , fpropLocEntry  :: !Entry
    +  , fpropTsEntry   :: !Entry
    +  , fpropModEntry  :: !Entry
    +  , fpropAcEntry   :: !Entry
    +  , fpropFTEntry   :: !Entry
    +  , fpropPermEntry :: !Entry
    +  , fpropLDEntry   :: !Entry
    +}
    +
    +
    +-- |FM-wide settings.
    +data FMSettings = MkFMSettings {
    +    showHidden :: !Bool
    +  , isLazy     :: !Bool
    +  , iconSize   :: !Int
    +}
    +
    +data FMView = FMTreeView !TreeView
    +            | FMIconView !IconView
    +
    +type Item = File FileInfo
    +
    +
    +
    +fmViewToContainer :: FMView -> Container
    +fmViewToContainer (FMTreeView x) =  castToContainer . toGObject $ x
    +fmViewToContainer (FMIconView x) =  castToContainer . toGObject $ x
    +
    +
    + diff --git a/src/HSFM-GUI-Gtk-Dialogs.html b/src/HSFM-GUI-Gtk-Dialogs.html new file mode 100644 index 0000000..0f41613 --- /dev/null +++ b/src/HSFM-GUI-Gtk-Dialogs.html @@ -0,0 +1,313 @@ + + + + + +src/HSFM/GUI/Gtk/Dialogs.hs + + + +
    {--
    +HSFM, a filemanager written in Haskell.
    +Copyright (C) 2016 Julian Ospald
    +
    +This program is free software; you can redistribute it and/or
    +modify it under the terms of the GNU General Public License
    +version 2 as published by the Free Software Foundation.
    +
    +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.
    +
    +You should have received a copy of the GNU General Public License
    +along with this program; if not, write to the Free Software
    +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    +--}
    +
    +{-# OPTIONS_HADDOCK ignore-exports #-}
    +
    +module HSFM.GUI.Gtk.Dialogs where
    +
    +
    +import Control.Exception
    +  (
    +    displayException
    +  , throwIO
    +  , IOException
    +  , catches
    +  , Handler(..)
    +  )
    +import Control.Monad
    +  (
    +    forM
    +  , when
    +  , void
    +  )
    +import Data.ByteString
    +  (
    +    ByteString
    +  )
    +import qualified Data.ByteString as BS
    +import Data.ByteString.UTF8
    +  (
    +    fromString
    +  )
    +import Data.Version
    +  (
    +    showVersion
    +  )
    +import Distribution.Package
    +  (
    +    PackageIdentifier(..)
    +  , PackageName(..)
    +  )
    +import Distribution.PackageDescription
    +  (
    +    GenericPackageDescription(..)
    +  , PackageDescription(..)
    +  )
    +import Distribution.PackageDescription.Parse
    +  (
    +    readPackageDescription
    +  )
    +import Distribution.Verbosity
    +  (
    +    silent
    +  )
    +import Graphics.UI.Gtk
    +import qualified HPath as P
    +import HPath.IO.Errors
    +import HSFM.FileSystem.FileType
    +import HSFM.FileSystem.UtilTypes
    +import HSFM.GUI.Glib.GlibString()
    +import HSFM.GUI.Gtk.Data
    +import HSFM.GUI.Gtk.Errors
    +import Paths_hsfm
    +  (
    +    getDataFileName
    +  )
    +import System.Glib.UTFString
    +  (
    +    GlibString
    +  )
    +import System.Posix.FilePath
    +  (
    +    takeFileName
    +  )
    +
    +
    +
    +
    +
    +
    +
    +
    +    ---------------------
    +    --[ Dialog popups ]--
    +    ---------------------
    +
    +
    +-- |Pops up an error Dialog with the given String.
    +showErrorDialog :: String -> IO ()
    +showErrorDialog str = do
    +  errorDialog <- messageDialogNew Nothing
    +                                  [DialogDestroyWithParent]
    +                                  MessageError
    +                                  ButtonsClose
    +                                  str
    +  _ <- dialogRun errorDialog
    +  widgetDestroy errorDialog
    +
    +
    +-- |Asks the user for confirmation and returns True/False.
    +showConfirmationDialog :: String -> IO Bool
    +showConfirmationDialog str = do
    +  confirmDialog <- messageDialogNew Nothing
    +                                    [DialogDestroyWithParent]
    +                                    MessageQuestion
    +                                    ButtonsYesNo
    +                                    str
    +  rID <- dialogRun confirmDialog
    +  widgetDestroy confirmDialog
    +  case rID of
    +    ResponseYes -> return True
    +    ResponseNo  -> return False
    +    _           -> return False
    +
    +
    +fileCollisionDialog :: ByteString -> IO (Maybe FCollisonMode)
    +fileCollisionDialog t = do
    +  chooserDialog <- messageDialogNew Nothing
    +                                    [DialogDestroyWithParent]
    +                                    MessageQuestion
    +                                    ButtonsNone
    +                                    (fromString "Target \"" `BS.append`
    +                                     t `BS.append`
    +                                     fromString "\" exists, how to proceed?")
    +  _ <- dialogAddButton chooserDialog "Cancel"        (ResponseUser 0)
    +  _ <- dialogAddButton chooserDialog "Overwrite"     (ResponseUser 1)
    +  _ <- dialogAddButton chooserDialog "Overwrite all" (ResponseUser 2)
    +  _ <- dialogAddButton chooserDialog "Skip"          (ResponseUser 3)
    +  _ <- dialogAddButton chooserDialog "Rename"        (ResponseUser 4)
    +  rID <- dialogRun chooserDialog
    +  widgetDestroy chooserDialog
    +  case rID of
    +    ResponseUser 0 -> return Nothing
    +    ResponseUser 1 -> return (Just Overwrite)
    +    ResponseUser 2 -> return (Just OverwriteAll)
    +    ResponseUser 3 -> return (Just Skip)
    +    ResponseUser 4 -> do
    +      mfn   <- textInputDialog (fromString "Enter new name") (takeFileName t)
    +      forM mfn $ \fn -> do
    +        pfn <- P.parseFn (fromString fn)
    +        return $ Rename pfn
    +    _              -> throwIO UnknownDialogButton
    +
    +
    +renameDialog :: ByteString -> IO (Maybe FCollisonMode)
    +renameDialog t = do
    +  chooserDialog <- messageDialogNew Nothing
    +                                    [DialogDestroyWithParent]
    +                                    MessageQuestion
    +                                    ButtonsNone
    +                                    (fromString "Target \"" `BS.append`
    +                                     t `BS.append`
    +                                     fromString "\" exists, how to proceed?")
    +  _ <- dialogAddButton chooserDialog "Cancel"        (ResponseUser 0)
    +  _ <- dialogAddButton chooserDialog "Skip"          (ResponseUser 1)
    +  _ <- dialogAddButton chooserDialog "Rename"        (ResponseUser 2)
    +  rID <- dialogRun chooserDialog
    +  widgetDestroy chooserDialog
    +  case rID of
    +    ResponseUser 0 -> return Nothing
    +    ResponseUser 1 -> return (Just Skip)
    +    ResponseUser 2 -> do
    +      mfn   <- textInputDialog (fromString "Enter new name") (takeFileName t)
    +      forM mfn $ \fn -> do
    +        pfn <- P.parseFn (fromString fn)
    +        return $ Rename pfn
    +    _              -> throwIO UnknownDialogButton
    +
    +
    +-- |Shows the about dialog from the help menu.
    +showAboutDialog :: IO ()
    +showAboutDialog = do
    +  ad       <- aboutDialogNew
    +  lstr     <- Prelude.readFile =<< getDataFileName "LICENSE"
    +  hsfmicon <- pixbufNewFromFile =<< getDataFileName "data/Gtk/icons/hsfm.png"
    +  pdesc    <- fmap packageDescription
    +                   (readPackageDescription silent
    +                     =<< getDataFileName "hsfm.cabal")
    +  set ad
    +    [ aboutDialogProgramName  := (unPackageName . pkgName . package) pdesc
    +    , aboutDialogName         := (unPackageName . pkgName . package) pdesc
    +    , aboutDialogVersion      := (showVersion . pkgVersion . package) pdesc
    +    , aboutDialogCopyright    := copyright pdesc
    +    , aboutDialogComments     := description pdesc
    +    , aboutDialogLicense      := Just lstr
    +    , aboutDialogWebsite      := homepage pdesc
    +    , aboutDialogAuthors      := [author pdesc]
    +    , aboutDialogLogo         := Just hsfmicon
    +    , aboutDialogWrapLicense  := True
    +    ]
    +  _ <- dialogRun ad
    +  widgetDestroy ad
    +
    +
    +-- |Carry out an IO action with a confirmation dialog.
    +-- If the user presses "No", then do nothing.
    +withConfirmationDialog :: String -> IO () -> IO ()
    +withConfirmationDialog str io = do
    +  run <- showConfirmationDialog str
    +  when run io
    +
    +
    +-- |Execute the given IO action. If the action throws exceptions,
    +-- visualize them via 'showErrorDialog'.
    +withErrorDialog :: IO a -> IO ()
    +withErrorDialog io =
    +  catches (void io)
    +    [ Handler (\e -> showErrorDialog
    +                       $ displayException (e :: IOException))
    +    , Handler (\e -> showErrorDialog
    +                       $ displayException (e :: HPathIOException))
    +    ]
    +
    +
    +-- |Asks the user which directory copy mode he wants via dialog popup
    +-- and returns 'DirCopyMode'.
    +textInputDialog :: GlibString string
    +                => string   -- ^ window title
    +                -> string   -- ^ initial text in input widget
    +                -> IO (Maybe String)
    +textInputDialog title inittext = do
    +  chooserDialog <- messageDialogNew Nothing
    +                                    [DialogDestroyWithParent]
    +                                    MessageQuestion
    +                                    ButtonsNone
    +                                    title
    +  entry <- entryNew
    +  entrySetText entry inittext
    +  cbox <- dialogGetActionArea chooserDialog
    +  _ <- dialogAddButton chooserDialog "Ok"     (ResponseUser 0)
    +  _ <- dialogAddButton chooserDialog "Cancel" (ResponseUser 1)
    +  boxPackStart (castToBox cbox) entry PackNatural 5
    +  widgetShowAll chooserDialog
    +  rID <- dialogRun chooserDialog
    +  ret <- case rID of
    +           -- TODO: make this more safe
    +           ResponseUser 0 -> Just <$> entryGetText entry
    +           ResponseUser 1 -> return Nothing
    +           _              -> throwIO UnknownDialogButton
    +  widgetDestroy chooserDialog
    +  return ret
    +
    +
    +showFilePropertyDialog :: [Item] -> MyGUI -> MyView -> IO ()
    +showFilePropertyDialog [item] mygui _ = do
    +  dialog <- messageDialogNew Nothing
    +                             [DialogDestroyWithParent]
    +                             MessageInfo
    +                             ButtonsNone
    +                             "File Properties"
    +
    +  let fprop' = fprop mygui
    +      grid   = fpropGrid fprop'
    +
    +  entrySetText (fpropFnEntry fprop')  (maybe BS.empty P.fromRel
    +                                        $ P.basename . path $ item)
    +  entrySetText (fpropLocEntry fprop') (P.fromAbs . P.dirname . path $ item)
    +  entrySetText (fpropTsEntry fprop')  (fromFreeVar (show . fileSize) item)
    +  entrySetText (fpropModEntry fprop') (packModTime item)
    +  entrySetText (fpropAcEntry fprop')  (packAccessTime item)
    +  entrySetText (fpropFTEntry fprop')  (packFileType item)
    +  entrySetText (fpropPermEntry fprop')
    +               (tail $ packPermissions item) -- throw away the filetype part
    +  case packLinkDestination item of
    +    (Just dest) -> do
    +      widgetSetSensitive (fpropLDEntry fprop') True
    +      entrySetText (fpropLDEntry fprop') dest
    +    Nothing     -> do
    +      widgetSetSensitive (fpropLDEntry fprop') False
    +      entrySetText (fpropLDEntry fprop') "( Not a symlink )"
    +
    +
    +  cbox <- dialogGetActionArea dialog
    +  _ <- dialogAddButton dialog "Ok"     (ResponseUser 0)
    +  _ <- dialogAddButton dialog "Cancel" (ResponseUser 1)
    +  boxPackStart (castToBox cbox) grid PackNatural 5
    +
    +  widgetShowAll dialog
    +  _ <- dialogRun dialog
    +
    +  -- make sure our grid does not get destroyed
    +  containerRemove (castToBox cbox) grid
    +
    +  widgetDestroy dialog
    +
    +  return ()
    +showFilePropertyDialog _ _ _ = return ()
    +
    +
    + diff --git a/src/HSFM-GUI-Gtk-Errors.html b/src/HSFM-GUI-Gtk-Errors.html new file mode 100644 index 0000000..7e738dd --- /dev/null +++ b/src/HSFM-GUI-Gtk-Errors.html @@ -0,0 +1,45 @@ + + + + + +src/HSFM/GUI/Gtk/Errors.hs + + + +
    {--
    +HSFM, a filemanager written in Haskell.
    +Copyright (C) 2016 Julian Ospald
    +
    +This program is free software; you can redistribute it and/or
    +modify it under the terms of the GNU General Public License
    +version 2 as published by the Free Software Foundation.
    +
    +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.
    +
    +You should have received a copy of the GNU General Public License
    +along with this program; if not, write to the Free Software
    +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    +--}
    +
    +{-# OPTIONS_HADDOCK ignore-exports #-}
    +
    +-- |Provides error handling for Gtk.
    +module HSFM.GUI.Gtk.Errors where
    +
    +
    +import Control.Exception
    +import Data.Typeable
    +
    +
    +
    +data GtkException = UnknownDialogButton
    +  deriving (Show, Typeable)
    +
    +instance Exception GtkException
    +
    +
    + diff --git a/src/HSFM-GUI-Gtk-Icons.html b/src/HSFM-GUI-Gtk-Icons.html new file mode 100644 index 0000000..6b978bd --- /dev/null +++ b/src/HSFM-GUI-Gtk-Icons.html @@ -0,0 +1,82 @@ + + + + + +src/HSFM/GUI/Gtk/Icons.hs + + + +
    {--
    +HSFM, a filemanager written in Haskell.
    +Copyright (C) 2016 Julian Ospald
    +
    +This program is free software; you can redistribute it and/or
    +modify it under the terms of the GNU General Public License
    +version 2 as published by the Free Software Foundation.
    +
    +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.
    +
    +You should have received a copy of the GNU General Public License
    +along with this program; if not, write to the Free Software
    +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    +--}
    +
    +{-# OPTIONS_HADDOCK ignore-exports #-}
    +
    +-- |Module for Gtk icon handling.
    +module HSFM.GUI.Gtk.Icons where
    +
    +
    +import Data.Maybe
    +  (
    +    fromJust
    +  )
    +import Graphics.UI.Gtk
    +import Paths_hsfm
    +  (
    +    getDataFileName
    +  )
    +
    +
    +-- |Icon type we use in our GUI.
    +data GtkIcon = IFolder
    +             | SymL
    +             | IFile
    +             | IError
    +
    +
    +-- |Gets an icon from the default icon theme and falls back to project-icons
    +-- if not found. The requested icon size is not guaranteed.
    +getIcon :: GtkIcon    -- ^ icon we want
    +        -> IconTheme  -- ^ which icon theme to get the icon from
    +        -> Int        -- ^ requested icon size
    +        -> IO Pixbuf
    +getIcon icon itheme isize = do
    +  let iname = iconToStr icon
    +  hasicon <- iconThemeHasIcon itheme iname
    +  case hasicon of
    +    True -> fromJust <$> iconThemeLoadIcon itheme iname isize
    +                                           IconLookupUseBuiltin
    +    False -> pixbufNewFromFile =<< getDataFileName
    +                                    ("data/Gtk/icons/" ++ iname ++ ".png")
    +  where
    +    iconToStr IFolder = "gtk-directory"
    +    iconToStr IFile   = "gtk-file"
    +    iconToStr IError  = "error"
    +    iconToStr SymL    = "emblem-symbolic-link"
    +
    +
    +getSymlinkIcon :: GtkIcon -> IconTheme -> Int -> IO Pixbuf
    +getSymlinkIcon icon itheme isize = do
    +  pix    <- pixbufCopy =<< getIcon icon itheme isize
    +  sympix <- getIcon SymL itheme isize
    +
    +  pixbufScale sympix pix 0 0 12 12 0 0 0.5 0.5 InterpNearest
    +
    +  return pix
    +
    + diff --git a/src/HSFM-GUI-Gtk-MyGUI.html b/src/HSFM-GUI-Gtk-MyGUI.html new file mode 100644 index 0000000..cc5e42d --- /dev/null +++ b/src/HSFM-GUI-Gtk-MyGUI.html @@ -0,0 +1,108 @@ + + + + + +src/HSFM/GUI/Gtk/MyGUI.hs + + + +
    {--
    +HSFM, a filemanager written in Haskell.
    +Copyright (C) 2016 Julian Ospald
    +
    +This program is free software; you can redistribute it and/or
    +modify it under the terms of the GNU General Public License
    +version 2 as published by the Free Software Foundation.
    +
    +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.
    +
    +You should have received a copy of the GNU General Public License
    +along with this program; if not, write to the Free Software
    +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    +--}
    +
    +{-# LANGUAGE RecordWildCards #-}
    +{-# OPTIONS_HADDOCK ignore-exports #-}
    +
    +module HSFM.GUI.Gtk.MyGUI where
    +
    +
    +import Control.Concurrent.STM
    +  (
    +    newTVarIO
    +  )
    +import Graphics.UI.Gtk
    +import HSFM.FileSystem.UtilTypes
    +import HSFM.GUI.Gtk.Data
    +import Paths_hsfm
    +  (
    +    getDataFileName
    +  )
    +
    +
    +
    +
    +    -------------------------
    +    --[ Main Window Setup ]--
    +    -------------------------
    +
    +
    +-- |Set up the GUI. This only creates the permanent widgets.
    +createMyGUI :: IO MyGUI
    +createMyGUI = do
    +
    +  let settings' = MkFMSettings False True 24
    +  settings <- newTVarIO settings'
    +  operationBuffer <- newTVarIO None
    +
    +  builder <- builderNew
    +  builderAddFromFile builder =<< getDataFileName "data/Gtk/builder.xml"
    +
    +  -- get the pre-defined gui widgets
    +  rootWin           <- builderGetObject builder castToWindow
    +                       "rootWin"
    +  menubarFileQuit   <- builderGetObject builder castToImageMenuItem
    +                       "menubarFileQuit"
    +  menubarHelpAbout  <- builderGetObject builder castToImageMenuItem
    +                      "menubarHelpAbout"
    +  statusBar         <- builderGetObject builder castToStatusbar
    +                       "statusBar"
    +  clearStatusBar    <- builderGetObject builder castToButton
    +                       "clearStatusBar"
    +  fpropGrid         <- builderGetObject builder castToGrid
    +                       "fpropGrid"
    +  fpropFnEntry      <- builderGetObject builder castToEntry
    +                       "fpropFnEntry"
    +  fpropLocEntry     <- builderGetObject builder castToEntry
    +                       "fpropLocEntry"
    +  fpropTsEntry      <- builderGetObject builder castToEntry
    +                       "fpropTsEntry"
    +  fpropModEntry     <- builderGetObject builder castToEntry
    +                       "fpropModEntry"
    +  fpropAcEntry      <- builderGetObject builder castToEntry
    +                       "fpropAcEntry"
    +  fpropFTEntry      <- builderGetObject builder castToEntry
    +                       "fpropFTEntry"
    +  fpropPermEntry    <- builderGetObject builder castToEntry
    +                       "fpropPermEntry"
    +  fpropLDEntry      <- builderGetObject builder castToEntry
    +                       "fpropLDEntry"
    +  notebook          <- builderGetObject builder castToNotebook
    +                       "notebook"
    +
    +  -- construct the gui object
    +  let menubar = MkMenuBar {..}
    +  let fprop = MkFilePropertyGrid {..}
    +  let mygui  = MkMyGUI {..}
    +
    +  -- sets the default icon
    +  _ <- windowSetDefaultIconFromFile
    +         =<< getDataFileName "data/Gtk/icons/hsfm.png"
    +
    +  return mygui
    +
    + diff --git a/src/HSFM-GUI-Gtk-MyView.html b/src/HSFM-GUI-Gtk-MyView.html new file mode 100644 index 0000000..00aa08f --- /dev/null +++ b/src/HSFM-GUI-Gtk-MyView.html @@ -0,0 +1,467 @@ + + + + + +src/HSFM/GUI/Gtk/MyView.hs + + + +
    {--
    +HSFM, a filemanager written in Haskell.
    +Copyright (C) 2016 Julian Ospald
    +
    +This program is free software; you can redistribute it and/or
    +modify it under the terms of the GNU General Public License
    +version 2 as published by the Free Software Foundation.
    +
    +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.
    +
    +You should have received a copy of the GNU General Public License
    +along with this program; if not, write to the Free Software
    +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    +--}
    +
    +
    +
    +module HSFM.GUI.Gtk.MyView where
    +
    +
    +import Control.Concurrent.MVar
    +  (
    +    newEmptyMVar
    +  , putMVar
    +  , tryTakeMVar
    +  )
    +import Control.Concurrent.STM
    +  (
    +    newTVarIO
    +  , readTVarIO
    +  )
    +import Control.Exception
    +  (
    +    try
    +  , SomeException
    +  )
    +import Control.Monad
    +  (
    +    forM_
    +  )
    +import qualified Data.ByteString as BS
    +import Data.Foldable
    +  (
    +    for_
    +  )
    +import Data.Maybe
    +  (
    +    catMaybes
    +  , fromJust
    +  )
    +import HPath.IO.Errors
    +  (
    +    canOpenDirectory
    +  )
    +import Graphics.UI.Gtk
    +import {-# SOURCE #-} HSFM.GUI.Gtk.Callbacks (setViewCallbacks)
    +import HPath
    +  (
    +    Path
    +  , Abs
    +  )
    +import qualified HPath as P
    +import HSFM.FileSystem.FileType
    +import HSFM.GUI.Glib.GlibString()
    +import HSFM.GUI.Gtk.Data
    +import HSFM.GUI.Gtk.Icons
    +import HSFM.GUI.Gtk.Utils
    +import HSFM.Utils.IO
    +import Paths_hsfm
    +  (
    +    getDataFileName
    +  )
    +import Prelude hiding(readFile)
    +import System.INotify
    +  (
    +    addWatch
    +  , initINotify
    +  , killINotify
    +  , EventVariety(..)
    +  )
    +import System.Posix.FilePath
    +  (
    +    pathSeparator
    +  , hiddenFile
    +  )
    +
    +
    +
    +-- |Creates a new tab with its own view and refreshes the view.
    +newTab :: MyGUI -> IO FMView -> Path Abs -> IO MyView
    +newTab mygui iofmv path = do
    +  myview <- createMyView mygui iofmv
    +  i <- notebookAppendPage (notebook mygui) (viewBox myview)
    +       (maybe (P.fromAbs path) P.fromRel $ P.basename path)
    +  mpage <- notebookGetNthPage (notebook mygui) i
    +  forM_ mpage $ \page -> notebookSetTabReorderable (notebook mygui)
    +                                                   page
    +                                                   True
    +  refreshView mygui myview (Just path)
    +  return myview
    +
    +
    +-- |Constructs the initial MyView object with a few dummy models.
    +-- It also initializes the callbacks.
    +createMyView :: MyGUI
    +             -> IO FMView
    +             -> IO MyView
    +createMyView mygui iofmv = do
    +  inotify <- newEmptyMVar
    +  history <- newTVarIO ([],[])
    +
    +  builder <- builderNew
    +  builderAddFromFile builder =<< getDataFileName "data/Gtk/builder.xml"
    +
    +  -- create dummy models, so we don't have to use MVar
    +  rawModel <- newTVarIO =<< listStoreNew []
    +  filteredModel <- newTVarIO =<< (\x -> treeModelFilterNew x [])
    +                             =<< readTVarIO rawModel
    +  sortedModel <- newTVarIO =<< treeModelSortNewWithModel
    +                           =<< readTVarIO filteredModel
    +  cwd <- newEmptyMVar
    +  view' <- iofmv
    +  view  <- newTVarIO view'
    +
    +  urlBar            <- builderGetObject builder castToEntry
    +                       "urlBar"
    +  rcMenu            <- builderGetObject builder castToMenu
    +                       "rcMenu"
    +  rcFileOpen        <- builderGetObject builder castToImageMenuItem
    +                       "rcFileOpen"
    +  rcFileExecute     <- builderGetObject builder castToImageMenuItem
    +                       "rcFileExecute"
    +  rcFileNewRegFile  <- builderGetObject builder castToImageMenuItem
    +                       "rcFileNewRegFile"
    +  rcFileNewDir      <- builderGetObject builder castToImageMenuItem
    +                       "rcFileNewDir"
    +  rcFileCut         <- builderGetObject builder castToImageMenuItem
    +                       "rcFileCut"
    +  rcFileCopy        <- builderGetObject builder castToImageMenuItem
    +                       "rcFileCopy"
    +  rcFileRename      <- builderGetObject builder castToImageMenuItem
    +                       "rcFileRename"
    +  rcFilePaste       <- builderGetObject builder castToImageMenuItem
    +                       "rcFilePaste"
    +  rcFileDelete      <- builderGetObject builder castToImageMenuItem
    +                       "rcFileDelete"
    +  rcFileProperty    <- builderGetObject builder castToImageMenuItem
    +                       "rcFileProperty"
    +  rcFileIconView    <- builderGetObject builder castToImageMenuItem
    +                       "rcFileIconView"
    +  rcFileTreeView    <- builderGetObject builder castToImageMenuItem
    +                       "rcFileTreeView"
    +  upViewB           <- builderGetObject builder castToButton
    +                       "upViewB"
    +  homeViewB         <- builderGetObject builder castToButton
    +                       "homeViewB"
    +  refreshViewB      <- builderGetObject builder castToButton
    +                       "refreshViewB"
    +  scroll            <- builderGetObject builder castToScrolledWindow
    +                       "mainScroll"
    +  viewBox           <- builderGetObject builder castToBox
    +                         "viewBox"
    +
    +  let rcmenu = MkRightClickMenu {..}
    +  let myview = MkMyView {..}
    +
    +  -- set the bindings
    +  setViewCallbacks mygui myview
    +
    +  -- add the treeview to the scroll container
    +  let oview = fmViewToContainer view'
    +  containerAdd scroll oview
    +
    +  widgetShowAll viewBox
    +
    +  return myview
    +
    +
    +-- |Switch the existing view in `MyView` with the one that the
    +-- io action returns.
    +switchView :: MyGUI -> MyView -> IO FMView -> IO ()
    +switchView mygui myview iofmv = do
    +  cwd <- getCurrentDir myview
    +
    +  oldpage <- destroyView mygui myview
    +
    +  -- create new view and tab page where the previous one was
    +  nview <- createMyView mygui iofmv
    +  newpage <- notebookInsertPage (notebook mygui) (viewBox nview)
    +             (maybe (P.fromAbs $ path cwd) P.fromRel
    +                 $ P.basename . path $ cwd) oldpage
    +  notebookSetCurrentPage (notebook mygui) newpage
    +
    +  refreshView' mygui nview cwd
    +
    +
    +-- |Destroys the current view by disconnecting the watcher
    +-- and destroying the active FMView container.
    +--
    +-- Everything that needs to be done in order to forget about a
    +-- view needs to be done here.
    +--
    +-- Returns the page in the tab list this view corresponds to.
    +destroyView :: MyGUI -> MyView -> IO Int
    +destroyView mygui myview = do
    +  -- disconnect watcher
    +  mi <- tryTakeMVar (inotify myview)
    +  for_ mi $ \i -> killINotify i
    +
    +  page <- notebookGetCurrentPage (notebook mygui)
    +
    +  -- destroy old view and tab page
    +  view' <- readTVarIO $ view myview
    +  widgetDestroy (fmViewToContainer view')
    +  notebookRemovePage (notebook mygui) page
    +
    +  return page
    +
    +
    +-- |Createss an IconView.
    +createIconView :: IO FMView
    +createIconView = do
    +  iconv <- iconViewNew
    +  iconViewSetSelectionMode iconv SelectionMultiple
    +  iconViewSetColumns iconv (-1)
    +  iconViewSetSpacing iconv 2
    +  iconViewSetMargin iconv 0
    +  {- set iconv [ iconViewItemOrientation := OrientationHorizontal ] -}
    +  {- set iconv [ iconViewOrientation := OrientationHorizontal ] -}
    +
    +  return $ FMIconView iconv
    +
    +
    +-- |Creates a TreeView.
    +createTreeView :: IO FMView
    +createTreeView = do
    +  -- create the final view
    +  treeView <- treeViewNew
    +  -- set selection mode
    +  tvs <- treeViewGetSelection treeView
    +  treeSelectionSetMode tvs SelectionMultiple
    +
    +  -- set drag and drop
    +  tl <- targetListNew
    +  atom <- atomNew ("HSFM" :: String)
    +  targetListAdd tl atom [TargetSameApp] 0
    +  treeViewEnableModelDragDest treeView tl [ActionCopy]
    +  treeViewEnableModelDragSource treeView [Button1] tl [ActionCopy]
    +
    +  -- create final tree model columns
    +  renderTxt <- cellRendererTextNew
    +  renderPix <- cellRendererPixbufNew
    +  let ct = cellText   :: (CellRendererTextClass cr) => Attr cr String
    +      cp = cellPixbuf :: (CellRendererPixbufClass self) => Attr self Pixbuf
    +
    +  -- filename column
    +  cF <- treeViewColumnNew
    +  treeViewColumnSetTitle        cF ("Filename" :: String)
    +  treeViewColumnSetResizable    cF True
    +  treeViewColumnSetClickable    cF True
    +  treeViewColumnSetSortColumnId cF 1
    +  cellLayoutPackStart cF renderPix False
    +  cellLayoutPackStart cF renderTxt True
    +  _ <- treeViewAppendColumn treeView cF
    +  cellLayoutAddColumnAttribute cF renderPix cp $ makeColumnIdPixbuf 0
    +  cellLayoutAddColumnAttribute cF renderTxt ct $ makeColumnIdString 1
    +
    +  -- date column
    +  cMD <- treeViewColumnNew
    +  treeViewColumnSetTitle        cMD ("Date" :: String)
    +  treeViewColumnSetResizable    cMD True
    +  treeViewColumnSetClickable    cMD True
    +  treeViewColumnSetSortColumnId cMD 2
    +  cellLayoutPackStart cMD renderTxt True
    +  _ <- treeViewAppendColumn treeView cMD
    +  cellLayoutAddColumnAttribute cMD renderTxt ct $ makeColumnIdString 2
    +
    +  -- permissions column
    +  cP <- treeViewColumnNew
    +  treeViewColumnSetTitle        cP ("Permission" :: String)
    +  treeViewColumnSetResizable    cP True
    +  treeViewColumnSetClickable    cP True
    +  treeViewColumnSetSortColumnId cP 3
    +  cellLayoutPackStart cP renderTxt True
    +  _ <- treeViewAppendColumn treeView cP
    +  cellLayoutAddColumnAttribute cP renderTxt ct $ makeColumnIdString 3
    +
    +  return $ FMTreeView treeView
    +
    +
    +-- |Re-reads the current directory or the given one and updates the View.
    +-- This is more or less a wrapper around `refreshView'`
    +--
    +-- If the third argument is Nothing, it tries to re-read the current directory.
    +-- If that fails, it reads "/" instead.
    +--
    +-- If the third argument is (Just path) it tries to read "path". If that
    +-- fails, it reads "/" instead.
    +refreshView :: MyGUI
    +            -> MyView
    +            -> Maybe (Path Abs)
    +            -> IO ()
    +refreshView mygui myview mfp =
    +  case mfp of
    +    Just fp  -> do
    +      canopen <- canOpenDirectory fp
    +      if canopen
    +         then refreshView' mygui myview =<< readFile getFileInfo fp
    +         else refreshView mygui myview =<< getAlternativeDir
    +    Nothing  -> refreshView mygui myview =<< getAlternativeDir
    +    where
    +      getAlternativeDir = do
    +        ecd <- try (getCurrentDir myview) :: IO (Either SomeException
    +                                                     Item)
    +        case ecd of
    +          Right dir -> return (Just $ path dir)
    +          Left _    -> return (P.parseAbs $ BS.singleton pathSeparator)
    +
    +
    +-- |Refreshes the View based on the given directory.
    +--
    +-- If the directory is not a Dir or a Symlink pointing to a Dir, then
    +-- calls `refreshView` with the 3rd argument being Nothing.
    +refreshView' :: MyGUI
    +             -> MyView
    +             -> Item
    +             -> IO ()
    +refreshView' mygui myview SymLink { sdest = d@Dir{} } =
    +  refreshView' mygui myview d
    +refreshView' mygui myview item@Dir{} = do
    +  newRawModel  <- fileListStore item myview
    +  writeTVarIO (rawModel myview) newRawModel
    +
    +  view' <- readTVarIO $ view myview
    +
    +  _ <- tryTakeMVar (cwd myview)
    +  putMVar (cwd myview) item
    +
    +  -- get selected items
    +  tps <- getSelectedTreePaths mygui myview
    +  trs <- catMaybes <$> mapM (treeRowReferenceNew newRawModel) tps
    +
    +  constructView mygui myview
    +
    +  -- set notebook tab label
    +  page <- notebookGetCurrentPage (notebook mygui)
    +  child <- fromJust <$> notebookGetNthPage (notebook mygui) page
    +  notebookSetTabLabelText (notebook mygui) child
    +       (maybe (P.fromAbs $ path item) P.fromRel $ P.basename . path $ item)
    +
    +  -- reselect selected items
    +  -- TODO: not implemented for icon view yet
    +  case view' of
    +    FMTreeView treeView -> do
    +      tvs <- treeViewGetSelection treeView
    +      ntps <- mapM treeRowReferenceGetPath trs
    +      mapM_ (treeSelectionSelectPath tvs) ntps
    +    _ -> return ()
    +refreshView' mygui myview Failed{} = refreshView mygui myview Nothing
    +refreshView' _ _ _ = return ()
    +
    +
    +-- |Constructs the visible View with the current underlying mutable models,
    +-- which are retrieved from 'MyGUI'.
    +--
    +-- This sort of merges the components mygui and myview and fires up
    +-- the actual models.
    +constructView :: MyGUI
    +              -> MyView
    +              -> IO ()
    +constructView mygui myview = do
    +  settings' <- readTVarIO $ settings mygui
    +
    +  -- pix stuff
    +  iT           <- iconThemeGetDefault
    +  folderPix    <- getIcon IFolder iT (iconSize settings')
    +  folderSymPix <- getSymlinkIcon IFolder iT (iconSize settings')
    +  filePix      <- getIcon IFile iT (iconSize settings')
    +  fileSymPix   <- getSymlinkIcon IFile iT (iconSize settings')
    +  errorPix     <- getIcon IError iT (iconSize settings')
    +  let dirtreePix Dir{}           = folderPix
    +      dirtreePix FileLike{}      = filePix
    +      dirtreePix DirSym{}        = folderSymPix
    +      dirtreePix FileLikeSym{}   = fileSymPix
    +      dirtreePix Failed{}        = errorPix
    +      dirtreePix BrokenSymlink{} = errorPix
    +      dirtreePix _               = errorPix
    +
    +
    +  view' <- readTVarIO $ view myview
    +
    +  cdirp <- path <$> getCurrentDir myview
    +
    +  -- update urlBar
    +  entrySetText (urlBar myview) (P.fromAbs cdirp)
    +
    +  rawModel' <- readTVarIO $ rawModel myview
    +
    +  -- filtering
    +  filteredModel' <- treeModelFilterNew rawModel' []
    +  writeTVarIO (filteredModel myview) filteredModel'
    +  treeModelFilterSetVisibleFunc filteredModel' $ \iter -> do
    +     hidden <- showHidden <$> readTVarIO (settings mygui)
    +     item   <- treeModelGetRow rawModel' iter >>= (P.basename . path)
    +     if hidden
    +       then return True
    +       else return . not . hiddenFile . P.fromRel $ item
    +
    +  -- sorting
    +  sortedModel' <- treeModelSortNewWithModel filteredModel'
    +  writeTVarIO (sortedModel myview) sortedModel'
    +  treeSortableSetSortFunc sortedModel' 1 $ \iter1 iter2 -> do
    +      cIter1 <- treeModelFilterConvertIterToChildIter filteredModel' iter1
    +      cIter2 <- treeModelFilterConvertIterToChildIter filteredModel' iter2
    +      item1  <- treeModelGetRow rawModel' cIter1
    +      item2  <- treeModelGetRow rawModel' cIter2
    +      return $ compare item1 item2
    +  treeSortableSetSortColumnId sortedModel' 1 SortAscending
    +
    +  -- set values
    +  treeModelSetColumn rawModel' (makeColumnIdPixbuf 0)
    +                     dirtreePix
    +  treeModelSetColumn rawModel' (makeColumnIdString 1)
    +                     (P.toFilePath . fromJust . P.basename . path)
    +  treeModelSetColumn rawModel' (makeColumnIdString 2)
    +                     packModTime
    +  treeModelSetColumn rawModel' (makeColumnIdString 3)
    +                     packPermissions
    +
    +  -- update model of view
    +  case view' of
    +    FMTreeView treeView -> do
    +      treeViewSetModel treeView sortedModel'
    +      treeViewSetRubberBanding treeView True
    +    FMIconView iconView -> do
    +      iconViewSetModel iconView (Just sortedModel')
    +      iconViewSetPixbufColumn iconView
    +                              (makeColumnIdPixbuf 0 :: ColumnId item Pixbuf)
    +      iconViewSetTextColumn iconView
    +                            (makeColumnIdString 1 :: ColumnId item String)
    +
    +  -- add watcher
    +  mi <- tryTakeMVar (inotify myview)
    +  for_ mi $ \i -> killINotify i
    +  newi <- initINotify
    +  _ <- addWatch
    +         newi
    +         [Move, MoveIn, MoveOut, MoveSelf, Create, Delete, DeleteSelf]
    +         (P.fromAbs cdirp)
    +         (\_ -> postGUIAsync $ refreshView mygui myview (Just $ cdirp))
    +  putMVar (inotify myview) newi
    +
    +  return ()
    +
    + diff --git a/src/HSFM-GUI-Gtk-Utils.html b/src/HSFM-GUI-Gtk-Utils.html new file mode 100644 index 0000000..1da92c3 --- /dev/null +++ b/src/HSFM-GUI-Gtk-Utils.html @@ -0,0 +1,177 @@ + + + + + +src/HSFM/GUI/Gtk/Utils.hs + + + +
    {--
    +HSFM, a filemanager written in Haskell.
    +Copyright (C) 2016 Julian Ospald
    +
    +This program is free software; you can redistribute it and/or
    +modify it under the terms of the GNU General Public License
    +version 2 as published by the Free Software Foundation.
    +
    +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.
    +
    +You should have received a copy of the GNU General Public License
    +along with this program; if not, write to the Free Software
    +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    +--}
    +
    +{-# OPTIONS_HADDOCK ignore-exports #-}
    +
    +module HSFM.GUI.Gtk.Utils where
    +
    +
    +import Control.Concurrent.MVar
    +  (
    +    readMVar
    +  )
    +import Control.Concurrent.STM
    +  (
    +    readTVarIO
    +  )
    +import Data.Maybe
    +  (
    +    catMaybes
    +  , fromJust
    +  )
    +import Data.Traversable
    +  (
    +    forM
    +  )
    +import Graphics.UI.Gtk
    +import HSFM.FileSystem.FileType
    +import HSFM.GUI.Gtk.Data
    +import Prelude hiding(getContents)
    +
    +
    +
    +    -----------------
    +    --[ Utilities ]--
    +    -----------------
    +
    +
    +getSelectedTreePaths :: MyGUI -> MyView -> IO [TreePath]
    +getSelectedTreePaths _ myview = do
    +  view' <- readTVarIO $ view myview
    +  case view' of
    +    FMTreeView treeView -> do
    +      tvs   <- treeViewGetSelection treeView
    +      treeSelectionGetSelectedRows tvs
    +    FMIconView iconView ->
    +      iconViewGetSelectedItems iconView
    +
    +
    +-- |Gets the currently selected item of the treeView, if any.
    +getSelectedItems :: MyGUI
    +                 -> MyView
    +                 -> IO [Item]
    +getSelectedItems mygui myview = do
    +  tps   <- getSelectedTreePaths mygui myview
    +  catMaybes <$> mapM (rawPathToItem myview) tps
    +
    +
    +-- |Carry out an action on the currently selected item.
    +--
    +-- If there is no item selected, does nothing.
    +withItems :: MyGUI
    +          -> MyView
    +          -> (   [Item]
    +              -> MyGUI
    +              -> MyView
    +              -> IO ()) -- ^ action to carry out
    +          -> IO ()
    +withItems mygui myview io = do
    +  items <- getSelectedItems mygui myview
    +  io items mygui myview
    +
    +
    +-- |Create the 'ListStore' of files/directories from the current directory.
    +-- This is the function which maps the Data.DirTree data structures
    +-- into the GTK+ data structures.
    +fileListStore :: Item  -- ^ current dir
    +              -> MyView
    +              -> IO (ListStore Item)
    +fileListStore dt _ = do
    +  cs <- getContents getFileInfo dt
    +  listStoreNew cs
    +
    +
    +-- |Currently unsafe. This is used to obtain any item, which will
    +-- fail if there is none.
    +getFirstItem :: MyView
    +             -> IO Item
    +getFirstItem myview = do
    +  rawModel' <- readTVarIO $ rawModel myview
    +  iter      <- fromJust <$> treeModelGetIterFirst rawModel'
    +  treeModelGetRow rawModel' iter
    +
    +
    +-- |Reads the current directory from MyView.
    +--
    +-- This reads the MVar and may block the main thread if it's
    +-- empty.
    +getCurrentDir :: MyView
    +              -> IO Item
    +getCurrentDir myview = readMVar (cwd myview)
    +
    +
    +-- |Push a message to the status bar.
    +pushStatusBar :: MyGUI -> String -> IO (ContextId, MessageId)
    +pushStatusBar mygui str = do
    +  let sb = statusBar mygui
    +  cid <- statusbarGetContextId sb "FM Status"
    +  mid <- statusbarPush sb cid str
    +  return (cid, mid)
    +
    +
    +-- |Pop a message from the status bar.
    +popStatusbar :: MyGUI -> IO ()
    +popStatusbar mygui = do
    +  let sb = statusBar mygui
    +  cid <- statusbarGetContextId sb "FM Status"
    +  statusbarPop sb cid
    +
    +
    +-- |Turn a path on the rawModel into a path that we can
    +-- use at the outermost model layer.
    +rawPathToIter :: MyView -> TreePath -> IO (Maybe TreeIter)
    +rawPathToIter myview tp = do
    +  fmodel <- readTVarIO (filteredModel myview)
    +  smodel <- readTVarIO (sortedModel myview)
    +  msiter <- treeModelGetIter smodel tp
    +  forM msiter $ \siter -> do
    +    cIter <- treeModelSortConvertIterToChildIter smodel siter
    +    treeModelFilterConvertIterToChildIter fmodel cIter
    +
    +
    +-- |Turn a path on the rawModel into the corresponding item
    +-- that we can use at the outermost model layer.
    +rawPathToItem :: MyView -> TreePath -> IO (Maybe Item)
    +rawPathToItem myview tp = do
    +  rawModel' <- readTVarIO $ rawModel myview
    +  miter     <- rawPathToIter myview tp
    +  forM miter $ \iter -> treeModelGetRow rawModel' iter
    +
    +
    +-- |Makes sure the list is max 5. This is probably not very efficient
    +-- but we don't care, since it's a small list anyway.
    +addHistory :: Eq a => a -> [a] -> [a]
    +addHistory i [] = [i]
    +addHistory i xs@(x:_)
    +  | i == x                 = xs
    +  | length xs == maxLength = i : take (maxLength - 1) xs
    +  | otherwise              = i : xs
    +  where
    +    maxLength = 10
    +
    +
    + diff --git a/src/HSFM-Utils-MyPrelude.html b/src/HSFM-Utils-MyPrelude.html new file mode 100644 index 0000000..02625c3 --- /dev/null +++ b/src/HSFM-Utils-MyPrelude.html @@ -0,0 +1,47 @@ + + + + + +src/HSFM/Utils/MyPrelude.hs + + + +
    {--
    +HSFM, a filemanager written in Haskell.
    +Copyright (C) 2016 Julian Ospald
    +
    +This program is free software; you can redistribute it and/or
    +modify it under the terms of the GNU General Public License
    +version 2 as published by the Free Software Foundation.
    +
    +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.
    +
    +You should have received a copy of the GNU General Public License
    +along with this program; if not, write to the Free Software
    +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    +--}
    +
    +module HSFM.Utils.MyPrelude where
    +
    +
    +import Data.Default
    +import Data.List
    +
    +
    +
    +-- |Turns any list into a list of the same length with the values
    +-- being the indices.
    +-- E.g.: "abdasd" -> [0,1,2,3,4,5]
    +listIndices :: [a] -> [Int]
    +listIndices = findIndices (const True)
    +
    +
    +-- |A `maybe` flavor using the `Default` class.
    +maybeD :: (Default b) => (a -> b) -> Maybe a -> b
    +maybeD = maybe def
    +
    + diff --git a/src/Main.html b/src/Main.html new file mode 100644 index 0000000..b17855f --- /dev/null +++ b/src/Main.html @@ -0,0 +1,71 @@ + + + + + +src/HSFM/GUI/Gtk.hs + + + +
    {--
    +HSFM, a filemanager written in Haskell.
    +Copyright (C) 2015 Julian Ospald
    +
    +This program is free software; you can redistribute it and/or
    +modify it under the terms of the GNU General Public License
    +version 2 as published by the Free Software Foundation.
    +
    +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.
    +
    +You should have received a copy of the GNU General Public License
    +along with this program; if not, write to the Free Software
    +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    +--}
    +
    +{-# LANGUAGE OverloadedStrings #-}
    +{-# OPTIONS_HADDOCK ignore-exports #-}
    +
    +module Main where
    +
    +
    +import Data.Maybe
    +  (
    +    fromJust
    +  , fromMaybe
    +  )
    +import Graphics.UI.Gtk
    +import qualified HPath as P
    +import HSFM.GUI.Gtk.Callbacks
    +import HSFM.GUI.Gtk.Data
    +import HSFM.GUI.Gtk.MyGUI
    +import HSFM.GUI.Gtk.MyView
    +import Safe
    +  (
    +    headDef
    +  )
    +import qualified System.Posix.Env.ByteString as SPE
    +
    +
    +main :: IO ()
    +main = do
    +  _ <- initGUI
    +
    +  args <- SPE.getArgs
    +  let mdir = fromMaybe (fromJust $ P.parseAbs "/")
    +                       (P.parseAbs . headDef "/" $ args)
    +
    +  mygui <- createMyGUI
    +  _ <- newTab mygui createTreeView mdir
    +
    +  setGUICallbacks mygui
    +
    +  widgetShowAll (rootWin mygui)
    +
    +  _ <- mainGUI
    +  return ()
    +
    +
    + diff --git a/src/hscolour.css b/src/hscolour.css new file mode 100644 index 0000000..c15919e --- /dev/null +++ b/src/hscolour.css @@ -0,0 +1,5 @@ +.hs-keyglyph, .hs-layout {color: red;} +.hs-keyword {color: blue;} +.hs-comment, .hs-comment a {color: green;} +.hs-str, .hs-chr {color: teal;} +.hs-keyword, .hs-conid, .hs-varid, .hs-conop, .hs-varop, .hs-num, .hs-cpp, .hs-sel, .hs-definition {} diff --git a/synopsis.png b/synopsis.png new file mode 100644 index 0000000000000000000000000000000000000000..85fb86ec84907bcc86531dc82871948ff4d471fa GIT binary patch literal 11327 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 B5rhB$ literal 0 HcmV?d00001