/* $Id: e2_fileview.h 2097 2010-05-28 00:08:41Z tpgww $

Copyright (C) 2004-2009 tooar <tooar@emelfm2.net>

This file is part of emelFM2.
emelFM2 is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

emelFM2 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 emelFM2; see the file GPL. If not, see http://www.gnu.org/licenses.
*/

#ifndef __E2_FILEVIEW_H__
#define __E2_FILEVIEW_H__

#include "emelfm2.h"

//these are in same order as ascii <, =, >
typedef enum { LT, EQ, GT } Operator;
typedef enum { E2_REFRESH, E2_RECREATE, E2_CHANGE } E2_RefreshType;
typedef enum { CD_NOTFINISHED, CD_TIMEOUT, CD_SUCCESS } E2_CDType;
//filelist treestore column-number enumerator
enum { FILENAME = 0, SIZE, PERM, OWNER, GROUP, MODIFIED, ACCESSED, CHANGED, MAX_COLUMNS };
#define EXTENSION -1 //enum for sort action

//directory-read failure codes
enum
{
	E2DREAD_ENOENT,	//empty dir (not really an error)
	E2DREAD_NS,		//stat dir failed
	E2DREAD_DNR,	//dir not opened
	E2DREAD_DNCH,	//cannot cd into dir to poll its contents
	E2DREAD_DNF,	//read cancelled by user after timeout
	E2DREAD_ENOTH,	//failed to create thread when doing timed read
	E2DREAD_ENOMEM,	//not enough memory for storing data about read item
	E2DREAD_ELAST	//just an enumerator
};
#define E2DREAD_FAILED(ptr) (!(ptr == NULL || (gpointer)ptr > GUINT_TO_POINTER (E2DREAD_ENOMEM)))

typedef enum
{
	E2FSCASE_UNKNOWN,
	E2FSCASE_SENSITIVE,
	E2FSCASE_ANY,	//insensitive
	E2FSCASE_NEVER,	//tried to discover, but unable to do so
	E2FSCASE_VIRTUAL,
	E2FSCASE_NOCACHE = 16,	//a bitfag set for removable devices
	E2FSCASE_SENSITIVENOW,	//values corresponding to fixed devices
	E2FSCASE_ANYNOW,
	E2FSCASE_NOTNOW,
	E2FSCASE_VIRTUALNOW
} E2_FSSensitive;

typedef struct _E2_Listman
{
	E2_RefreshType refreshtype; //whether a view update is a refresh, recreate or cd
	struct _E2_ViewInfo *view;	//use this when re-starting a cd after timeout
	gchar *newpath;	//stored copy of place to open, non-NULL implies cd requested
	gboolean history;
	gboolean hook;
	VOLATILE gboolean cd_requested;	//TRUE when we can't yet cd using this data
	VOLATILE gint cd_working;	//1 to prevent re-entrant cd of the same filelist
//	guint timer;	//id of timer running a cd process

	VOLATILE gboolean refresh_requested;	//TRUE when something has proposed that the view be refreshed
	VOLATILE gint refresh_working;	//1 when a view-refresh is in progress
	VOLATILE gboolean norefresh;	//flag signalling refresh is disabled (though backend checks are not)

//	VOLATILE gboolean listing ; //TRUE during th "core" part of list re-creation
} E2_Listman;

typedef struct _E2_ViewInfo
{
	GtkListStore *store;
	GtkTreeModel *model;	//may be a filter model or standard
	GtkWidget *treeview;
	GtkTreeSelection *selection;	//pointer to selection for this view's treeview
	GHashTable *selected_names;  //names of selected items (for reselection), or NULL
	gint sort_column;	//copy of current sort column, can be <0
	gboolean extsort;	//TRUE when name-sorting is by extension
	GtkSortType sort_order; //copy of current sort order
	GtkWidget *sort_arrows[MAX_COLUMNS];
	GtkLabel *name_label;	//for showing active pane by changing label content
//	E2_FSType dirtype;	//flags for type of namespace this view belongs to
	E2_FSSensitive case_sensitive_names; //cache, FIXME needs to be cleared when removable device changes
#ifdef E2_VFS
	VOLATILE PlaceInfo *spacedata;	//pointer to data in relevant member of vpaths cache, NULL for mounted dir
//	vpath vdir;		//pointer to data in relevant member of vpaths cache
#endif
	gchar dir[PATH_MAX];	//path shown in this view (UTF-8, with trailing "/")
							//typically same as corresponding (freeable) rt->path,
							// ? but with easier access for regular usage
//	GList *dir_history; //list of structs with focused line etc for each opened dir in the current namespace
						//data are shared with app.dir_history
//#ifndef E2_FAM
	time_t dir_mtime;
	time_t dir_ctime;
//#endif
	GtkWidget *check_dirs; //filter sub-menu toggle-widget
	GtkWidget *check_name; //filter sub-menu toggle-widget
	struct
	{
		gchar *patternptr;
		GSList *compiled_patterns;	//list of _E2_SelectPattern's
		gboolean invert_mask;
		gboolean case_sensitive;
		gboolean active;
	} name_filter;
	GtkWidget *check_size;
	struct
	{
		size_t size;
		Operator op;
		gboolean active;
	} size_filter;
	GtkWidget *check_date;
	struct
	{
		time_t time;	//time_t may be int or long int
		Operator op;
		enum {MTIME, ATIME, CTIME} time_type;
		gboolean active;
	} date_filter;

	gboolean filtered_before;	//state of prior call to filter function
	gboolean filter_directories;
	guint filtercount;	//bumped at each re-filter, for e.g. thumbs dialog, to poll for filter-changes
	gboolean show_hidden;  //whether to display hidden items in this view
	guint total_items;	//total displayed and undisplayed items in the dir - 2 (to ignore . and ..)
	gint row;			//0-based index of most-recently clicked row in the treeview
	gint drop_row;		//0-based index of most-recently moused row during a drag operation
	gboolean lit;		//TRUE if drop-row is highlighted
	gboolean convert;	//TRUE when any item's name has non-ASCII char(s), so conversion is needed for all
//	E2_RefreshType refreshtype; //whether a view update is a refresh, recreate or cd
//	gboolean refresh_requested;	//TRUE when something has proposed that the view be refreshed
//	gboolean norefresh;	//flag signalling refresh is disabled (though backend checks are not)
//	gboolean listing ; //flag to block recursive filelist updates
	E2_Listman listcontrols;
	gchar last_find[NAME_MAX]; //buffer for storing names used in find task
	GHookList hook_refresh;	//data for functions to run during post-refresh idle-time function
} ViewInfo;

typedef struct _E2_FileInfo
{
	gchar filename[NAME_MAX+1];  //item basename, localised string
#ifdef E2_VFS
	//in a collection, each item can have any path
	vpath *vdir; //pointer to hashed dir data for this item, or NULL if view->dir applies
				 //path string is localised, with no trailing separator
#endif
	struct stat statbuf;	//sometimes-customised form of fs statbuf
} FileInfo;

//enable automatic logging of selected items, and re-selection
//#define TAG_ALL

typedef struct _E2_DirHistoryEntry
{
	gchar path[PATH_MAX];	//must be at start of stuct (struct ptr sometimes used for lists of strings)
#ifdef E2_VFS
	PlaceInfo *spacedata;	//pointer to data in relevant member of vpaths cache
#endif
	gchar firstname [NAME_MAX+1]; //copy of info->filename for 1st selected item
	gint selrow;	//liststore index of 1st selected row, -1 if no selection
	gint toprow;	//liststore index of top visible row
	E2_FSSensitive case_sensitive_names;
	GHashTable *selitems; //for use by tag-plugin or with TAG_ALL
} E2_DirHistoryEntry;

typedef struct _E2_SelectedItemInfo
{
	gchar filename[NAME_MAX+1];  //localised string no trailing /
/*	FileInfo info;
	gchar *filename;  //selected item name (except no trailing /), utf-8 string
#ifdef E2_INCLIST
	//use this if the store data is changed on the fly
	GtkTreeRowReference *ref;
#else
	//this is used for un-selecting liststore items on the fly
	GtkTreePath *path;
#endif
*/
} E2_SelectedItemInfo;

typedef struct _E2_CDwatch
{
	ViewInfo *view;	//data for view being changed (can't use E2_PaneRuntime due to circular includes)
	gchar *newpath;	//place to be opened, utf8 with trailing separator
	gint repeats;	//current retry counter
//	guint watchtimer_id; //id of timer that is watching for completion
	E2_CDType *completed_flag;	//store for flag to set when completion detected
} E2_CDwatch;

typedef struct _E2_DRead
{
	pthread_t aid;	//read thread ID, 0 when stopped
	pthread_t mid;	//monitor thread ID, 0 when stopped
	GtkWidget *dialog;	//too-slow dialog widget, or NULL
} E2_DRead;

typedef struct _E2_SelectPattern
{
	GPatternSpec *pspec;
	gboolean negated;
} E2_SelectPattern;

#define WAIT_FOR_REFRESH(view) \
	while (TRUE) \
	{ \
		gboolean __busy; \
		__busy = g_atomic_int_get (&view->listcontrols.refresh_working) \
			  || g_atomic_int_get (&view->listcontrols.cd_working); \
		if (!__busy) \
			break; \
		usleep (100000); \
	}

gint e2_fileview_ext_sort (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
	GtkSortType *direction);
gboolean e2_fileview_sort_column (gint colnum, ViewInfo *view);
void e2_fileview_refilter_list (ViewInfo *view);
void e2_fileview_filter_dirs_cb (GtkCheckMenuItem *widget, ViewInfo *view);
void e2_fileview_remove_filters_cb (GtkMenuItem *widget, ViewInfo *view);
void e2_fileview_initialize_filters (ViewInfo *view);

void e2_fileview_set_menu_position (GtkMenu *menu,
	gint *x, gint *y, gboolean *push_in, GtkWidget *treeview);
void e2_fileview_focus_row (ViewInfo *view, gint row,
	gboolean select_row, gboolean clear_selection,
	gboolean center, gboolean grab_focus);
//void e2_fileview_select_row_by_filename (ViewInfo *view, gchar *filename); unused
GHashTable *e2_fileview_log_selected_names (ViewInfo *view);
void e2_fileview_reselect_names (ViewInfo *view);
void e2_fileview_translate_cols_array (gint *src_array,
	gint *dest_array, gint size);
void e2_fileview_switch_views (void);
//void e2_fileview_switch_views_simple (void);
void e2_fileview_set_font (void);
void e2_fileview_set_row_background (ViewInfo *view,
	GtkTreeIter *iter, GdkColor *color);
void e2_fileview_clear_row_background (ViewInfo *view,
	GtkTreeIter *iter);
void e2_fileview_update_col_cachedata (void);
void e2_fileview_get_scroll_data (ViewInfo *view, gint *leftcol, gint *toprow);
gboolean e2_fileview_scroll_to_position (ViewInfo *view, gint leftcol, gint toprow);
//gint e2_fileview_find_name_col (ViewInfo *view); unused
gboolean e2_fileview_prepare_list (ViewInfo *view);
void e2_fileview_scroll_list (GThread *viewthread);
gpointer e2_fileview_refresh_list (ViewInfo *view);
gboolean e2_fileview_treehash_free (GHashTable *data);
gboolean e2_fileview_cd_watch (E2_CDwatch *data);
gboolean e2_fileview_cd_manage (E2_Listman *data);
GtkWidget *e2_fileview_create_list (ViewInfo *view);
void e2_fileview_select_all (GtkWidget *widget, ViewInfo *view);
void e2_fileview_clean_selected (GPtrArray *selected);
void e2_fileview_clean1_history (gpointer data);
GPtrArray *e2_fileview_get_selected (ViewInfo *view);
GList *e2_fileview_get_selected_local (ViewInfo *view);
FileInfo *e2_fileview_get_selected_first_local (ViewInfo *view, gboolean updir);
gchar *e2_fileview_get_row_name (ViewInfo *view, gint row);
void e2_fileview_register_keybindings (GtkWidget *treeview, ViewInfo *view);
#ifdef E2_MOUSECUSTOM
void e2_fileview_register_pointerbindings (GtkWidget *treeview, ViewInfo *view);
#endif
#endif //ndef __E2_FILEVIEW_H__
