function pal = xbat_palette(str)

% xbat_palette - main palette to provide access to files
% ------------------------------------------------------
%
% pal = xbat_palette
%
%     = xbat_palette(str)
%
% Input:
% ------
%  str - command string
%
% Output:
% -------
%  pal - palette handle

%--------------------------------
% Author: Harold Figueroa
%--------------------------------
% $Revision: 6276 $
% $Date: 2006-08-22 02:01:51 -0400 (Tue, 22 Aug 2006) $
%--------------------------------

%--------------------------------------------------------------
% CHECK FOR PALETTE
%--------------------------------------------------------------

pal = get_palette(0, 'XBAT');

%--
% position palette and possibly perform command
%--

if ~isempty(pal)

	if ~nargout
		position_palette(pal, 0, 'top right');
	end
	
	if nargin
		control_callback([], pal, str);
	end
		
	return;
	
end

%--------------------------------------------------------------
% CREATE PALETTE
%--------------------------------------------------------------

%--
% get user
%--

user = get_active_user;

%--
% create palette controls
%--

control = xbat_palette_controls(user);

%--
% configure palette controls
%--

opt = control_group;

opt.width = 14;

opt.top = 0;

opt.bottom = 1.25;

opt.header_color = get_extension_color('root');

[positions, tile] = compile_positions(control, opt);

%--------------------------------------------------------------
% RENDER PALETTE
%--------------------------------------------------------------

%--
% create palette
%--

pal = control_group([], @xbat_controls_callback, 'XBAT', control, opt);

user_menu(pal);

session_menu(pal, user);

text_menu(pal);

%--
% tag and position palette
%--

set(pal, 'tag', 'XBAT_PALETTE::XBAT');

position_palette(pal, 0, 'top right');


% NOTE: this would close the 'Logs' header on open

% headers = get_palette_headers(pal);
% 
% ix = find(strcmp({headers.label}, 'Logs'));
% 
% if ~isempty(ix)
% 	palette_toggle(pal, headers(ix).handles.toggle, 'close');
% end

%--------------------------------------------------------------
% ADD CONTEXT MENUS
%--------------------------------------------------------------

% NOTE: the context menus contain many important commands, document this

% ALSO: in particular these should lead to a variety of batch operation interfaces

%--------------------
% Sounds
%--------------------

%--
% main context menu
%--

g = findobj(pal,'tag','Sounds','style','listbox');

% NOTE: this two step process is cumbersome, create shortcut

temp = uicontextmenu('parent',pal); set(g,'uicontextmenu',temp);

L = { ...
	'Open', ...
	'Open in New Window', ...
	'Configure ...', ...
	'Action', ...
	'Copy to Library', ...
	'Show Files ...', ...
	'Delete ...' ...
};

n = length(L);

S = bin2str(zeros(1,n));
S{4} = 'on';
S{end - 1} = 'on';
S{end} = 'on';

temp = menu_group(temp, @xbat_controls_callback, L, S);

set(temp,'tag','Sounds');

%--
% add libraries to menu
%--

L = library_name_list(user);

tmp2 = menu_group(get_menu(temp,'Copy to Library'),@xbat_controls_callback,L);

set(tmp2,'tag','Sounds');

	
%-------------------------
% Logs
%-------------------------

%--
% main
%--

g = findobj(pal,'tag','Logs','style','listbox');

tmp = uicontextmenu('parent',pal);

set(g,'uicontextmenu',tmp);

L = { ...
	'Open', ...
	'Open in New Window', ...
	'Action', ...
	'Export Clips ...', ...
	'Show Files ...', ...
	'Delete ...' ...
};

n = length(L);

S = bin2str(zeros(1,n));
S{3} = 'on';
S{end - 1} = 'on';
S{end} = 'on';

tmp = menu_group(tmp,@xbat_controls_callback,L,S);

set(tmp,'tag','Logs');

%--
% library
%--

% NOTE: should the copy to library function should be extended to logs?

% L = struct_field(user.library,'name');
% 
% tmp = menu_group(get_menu(tmp,'Copy to Library'),@xbat_controls_callback,L);
% 
% set(tmp,'tag','Sounds');

%--------------------
% Attach Actions
%--------------------

type = {'sound', 'log'};

for k = 1:length(type)

	%--
	% find parent action menu
	%--

	name = title_caps([type{k}, 's']);
		
	handles = get_control(pal, name, 'handles');

	par = findobj(get(handles.obj, 'uicontextmenu'), 'label', 'Action');

	if isempty(par)
		continue;
	end

	%--
	% attach actions menu
	%--
	
	action_menu(par, type{k});
	
end

%--------------------------------------------------------------
% UPDATE PALETTE
%--------------------------------------------------------------

pal = xbat_palette('Library');

% %--
% % do this by reopening the current library
% %--
% 
% g = findobj(pal, 'tag', 'Library', 'style', 'popupmenu');
% 
% feval(@xbat_controls_callback, g, []);


%--------------------------------------------------------------
% XBAT PALETTE CALLBACK FUNCTION
%--------------------------------------------------------------

function xbat_controls_callback(obj, eventdata)

%--
% get context from object handle
%--

if strcmp(get(obj, 'type'), 'uimenu')
	
	%--
	% handle palette menus, typically contextual menus
	%--
	
	pal = get(get(obj, 'parent'), 'parent'); % palette figure handle
	
	tag = get(obj, 'tag'); % the callback is largely determined by the parent controls, its name is in the tag
	
	action = get(obj, 'label'); % this is the label on the menu item
	
else
	
	%--
	% handle other controls in palette
	%--
	
	pal = get(obj, 'parent'); % palette figure handle
	
	tag = get(obj, 'tag'); % this is the name of the control
	
	action = ''; % the action is typically provided by the control tag, no need for action
	
end

%--
% perform action
%--

switch tag
	
	%------------------------------------------------------------------
	% CHANGE USER
	%------------------------------------------------------------------
	
	case 'User'
		
		%--
		% get user name from control
		%--
		
		value = get_control(pal, 'User', 'value'); value = value{1};
		
		%-------------------------
		% UPDATE USER
		%-------------------------

		user = get_users('name', value);

		if ~isempty(user) && ~isequal(user, get_active_user)
			
			set_active_user(user);
			
			user_menu(pal);
			
			session_menu(pal, user);
			
		else
			
			% stay on current user if the user to change to is not
			% available, this is not a robust way of handling the missing
			% user, however it should work most of the time
			
			user = get_active_user;
			
			names = struct_field(get_users, 'name');
			
			% put default user on top
			
			ix = find(strcmp('Default', names));
		
			if ~isempty(ix)
				names(ix) = []; names = {'Default', names{:}};
			end
		
			ix = find(strcmp(user.name, names));
			
			set(obj, ...
				'string', names, ...
				'value', ix ...
			);

		end
		
		%--
		% disable delete user for default user
		%--
		
		if strcmp(user.name, 'Default')
			set_control(pal, 'edit_user', 'enable', 'off');
		else
			set_control(pal, 'edit_user', 'enable', 'on');
		end
			
		%--
		% disable unsubscribe for users only subscribed to default
		%--
		
		list = library_name_list(user);
		
		val = min(user.active, length(list));
		
		if length(list) < 2	
			set_control(pal, 'unsubscribe_user', 'enable', 'off');
		end
			
		%-------------------------
		% UPDATE LIBRARY
		%-------------------------
		
		% FIXME: change this to something more cautious, never break!!
		
		% update the library control value
		
		g = findobj(pal, 'tag', 'Library', 'style', 'popupmenu');		
		
		set(g, ...
			'string',list, 'value',val ...
		);
	
		xbat_controls_callback(g); 
		
		%------------------------
		% UPDATE CONTEXT MENUS
		%------------------------
		
		update_context_menus(pal); 

	%------------------------------------------------------------------
	% ADD USER
	%------------------------------------------------------------------
	
	case 'add_user'
		
		user = new_user_dialog; 
		
		if isempty(user)
			return;
		end
		
		set_active_user(user);
		
		user_menu(pal);
		
		session_menu(user);

	%------------------------------------------------------------------
	% EDIT USER
	%------------------------------------------------------------------		
		
	case 'edit_user'
	
		set_active_user(new_user_dialog(get_active_user));
			
	%------------------------------------------------------------------
	% DELETE USER
	%------------------------------------------------------------------
	
	case 'Delete User'
		
		%--
		% delete user
		%--
		
		% NOTE: confirmation dialog is presented, and user is backed up
		
		delete_user(get_active_user);
		
	%------------------------------------------------------------------
	% LOAD LIBRARY (SET ACTIVE LIBRARY)
	%------------------------------------------------------------------
	
	case 'Library'
		
		%--
		% get control value
		%--
		
		value = get(obj, 'string');
		
		libname = value{get(obj, 'value')};
		
		%-------------------------
		% UPDATE LIBRARY
		%-------------------------
		
		ix = find(strcmp(libname, library_name_list(get_active_user)));
		
		if isempty(ix)
			
			handles = get_control(pal, 'User', 'handles');
			
			xbat_controls_callback(handles.uicontrol.popupmenu);
			
			return;
			
		end
		
		user = get_active_user; user.active = ix;
		
		% NOTE: this should happen in 'user_save'
		
		user_save(user); set_active_user(user);
		
		% NOTE: we set the tooltip to display path of library
		
		set(obj,'tooltipstring',user.library{user.active});
			
		if strcmp(libname, 'Default')
			set_control(pal, 'unsubscribe_user', 'enable', 'off');
		else
			set_control(pal, 'unsubscribe_user', 'enable', 'on');
		end
		
		%-------------------------
		% UPDATE SOUNDS
		%-------------------------
		
		%--
		% update find sounds control, clear query and run callback.
		%--
		
		set_control(pal, 'find_sounds', 'value', '');
		
		g = findobj(pal, 'tag', 'find_sounds', 'style', 'edit'); 
				
		xbat_controls_callback(g);
		
		%--
		% update sound info
		%--
		
		g = findobj(pal,'tag','sound_info','style','listbox');
		
		set(g, ...
			'string',[], ...
			'value',[], ...
			'listboxtop',1, ...
			'enable','off' ...
		);
		
		%-------------------------
		% UPDATE COPY TO LIBRARY MENU
		%-------------------------
		
		g = findobj(pal,'tag','Sounds','style','listbox');
				
		g = findobj(get(get(g,'uicontextmenu'),'children'),'label','Copy to Library');
		
		delete(get(g, 'children'));
		
		list = library_name_list(user); active_lib = list{user.active};
		
		L = setdiff(list, active_lib);
				
		if ~isempty(L)
			
			set(g, 'enable', 'on');
			menu_group(g, @copy_to_library, L);
			
		else
			
			set(g, 'enable', 'off');
			
		end
		
		%-------------------------
		% UPDATE CONTEXT MENUS
		%-------------------------
		
		update_context_menus(pal);
	
	%------------------------------------------------------------------
	% NEW_LIBRARY
	%------------------------------------------------------------------
		
	case 'new_library'
		
		lib = new_library_dialog;
		
		if isempty(lib)
			return;
		end
	
		user = user_subscribe(lib, get_active_user);
		
		set_active_user(user.name);
		
		
	%------------------------------------------------------------------
	% SUBSCRIBE
	%------------------------------------------------------------------
		
	case 'subscribe_user'
		
		%--
		% get library information from dialog
		%--
		
		success = user_subscribe_dialog;
		
		if success	
			set_control(pal, 'unsubscribe_user', 'enable', 'on');	
		end

		
	%------------------------------------------------------------------
	% UNSUBSCRIBE
	%------------------------------------------------------------------
		
	case 'unsubscribe_user'
		
		%--
		% get user and library
		%--
		
		user_unsubscribe(get_active_library, get_active_user);
		
				
	%------------------------------------------------------------------
	% FIND SOUNDS
	%------------------------------------------------------------------
	
	case 'find_sounds'
		
		%------------------------------------------------------------------
		% FILTER AVAILABLE SOUNDS
		%------------------------------------------------------------------
		
		%--
		% get pattern
		%--
		
		pat = get(obj, 'string');
		
		%--
		% get available library sounds and filter using pattern
		%--
		
		% TODO: output and use indices to compute sound duration fast
		
		sounds = get_library_sounds;
		
		sound_names = filter_strings(sound_name(sounds), pat);
		
		% make sure sounds is a cell array
		
		if ischar(sound_names)
			sound_names = {sound_names};
		end
		
		%--
		% update sounds control
		%--
		
		% NOTE: the update of the listboxtop property is required
		
		g = findobj(pal, 'tag', 'Sounds', 'style', 'listbox');
		
		if isempty(sound_names)
			set(g, ...
				'string',{'(No Sounds Found)'}, ...
				'value',[], ...
				'listboxtop',1, ...
				'enable','off' ...
			);		
		else	
			set(g, ...
				'string',sound_names, ...
				'value',[], ...
				'listboxtop',1, ...
				'enable','on' ...
			);	
		end
		
		% also update sound label
		
		g = findobj(pal, 'tag', 'Sounds', 'style', 'text');
		
		% NOTE: when no selection occurred all the sounds are displayed
		
		if ~isempty(pat)
			sounds = get_library_sounds([], 'name', sound_names); 
		end
		
		set(g, 'string', ['Sounds  (', sound_info_str(sounds, 'multiple'), ')']);
		
		%--
		% update sound info
		%--
		
		g = findobj(pal, 'tag', 'sound_info', 'style', 'listbox');	
		
		set(g, ...
			'string',[], ...
			'value',[], ...
			'listboxtop',1, ...
			'enable','off' ...
		);
	
		%--
		% update find logs
		%--
		
		set_control(pal, 'find_logs', 'value', '');
		
		g = findobj(pal, 'tag', 'find_logs', 'style', 'edit'); 
		
		xbat_controls_callback(g);
		
		%-------------------------
		% UPDATE CONTEXT MENUS
		%-------------------------
		
		update_context_menus(pal);
		
	%------------------------------------------------------------------
	% SOUNDS ACTIONS
	%------------------------------------------------------------------
	
	case 'Sounds'
		
		%--
		% get detector names
		%--
		
		% NOTE: this list is used in the 'action' switch
		
		DET_NAME = struct_field(get_extensions('detectors'), 'name');
		
		%--
		% perform action
		%--
		
		switch (action)
			
			%------------------------------------------------------------------
			% CONFIGURE
			%------------------------------------------------------------------
			
			% NOTE: configure source in generic and format specific ways
			
			case 'Configure ...'
				
				%--
				% get selected sound name
				%--
				
				[ignore, name] = control_update([], pal, 'Sounds');
				
				if (length(name) > 1)
					return;
				end
				
				name = name{1};
				
				%--
				% check whether sound is open
				%--
				
				figs = get_xbat_figs('type', 'sound'); 
				
				% NOTE: the sound is not open if there are no browsers open
				
				if ~isempty(figs)
					
					%--
					% get browser tags
					%--
					
					% NOTE: these contain parseable library and sound info
					
					tags = get(figs, 'tag');
					
					if ischar(tags)
						tags = {tags};
					end
					
					for k = 1:length(tags)

						info = parse_tag(tags{k});

						if strcmpi(info.sound, name)
							
							str = sprintf([ ...
								'Open sounds cannot be configured.\n', ...
								'Please close ''', name, ''' before configuring.' ...
							]);
						
							warn_dialog(str, 'Configure'); return;
						
						end

					end
					
				end

				%--
				% get sound file format handler
				%--
				
				sound = get_library_sounds([], 'name', name);
				 
				switch lower(sound.type)
					
					case 'file'
						format = get_file_format(sound.file);
						
					case 'file stream'
						format = get_file_format(sound.file{1});
			
				end
				
% 				%--
% 				% format specific configure if needed
% 				%--
% 			
% 				% NOTE: file formats may have format specific options
% 				
% 				if (isempty(format.config))
% 					return;
% 				end
% 				
% 				sound = format.config('edit',sound);
				
				%--
				% generic configure
				%--
				
				% TODO: consider moving format specific configuration here
				

				sound = edit_sound_config(sound, get_active_library);
			
			%--------------------------------------------------------------
			% NEW LOG
			%--------------------------------------------------------------
				
			case 'New Log ...'
				
				new_log_dialog([], [], 'root');
				
			%------------------------------------------------------------------
			% OPEN AND OPEN IN NEW WINDOW
			%------------------------------------------------------------------
			
			% NOTE: one or many sounds may be opened at the same time
			
			case {'Open', 'Open in New Window'}
				
				%--
				% try to get string value from associated control
				%--
				
				g = findobj(pal,'tag','Sounds','style','listbox');

				L = get(g,'string');
				ix = get(g,'value'); 
				
				% return if there is no selection
				
				if isempty(ix)
					return;
				end
				
				% make sure value is in cell array
				
				if (length(ix) == 1)
					value = {L{ix}};
				else
					for k = 1:length(ix)
						value{k} = L{ix(k)};
					end
				end
								
				%--
				% open sounds in browser
				%--
				
				% set open in new window option
				
				if strcmp(action, 'Open')
					opt = 0;
				else
					opt = 1;
				end
				
				lib = get_active_library;
				
				for k = 1:length(value)	
					timer_stop; open_library_sound(value{k}, lib, opt);
				end
				
				timer_run;
												
			%------------------------------------------------------------------
			% DETECT (batch detection)
			%------------------------------------------------------------------
			
			% NOTE: this is a very preliminatr implementation of this idea
			
			case (DET_NAME)
				
				browser_detect_menu([], [action ' Batch']);
								
			%------------------------------------------------------------------
			% SHOW FILES ...
			%------------------------------------------------------------------
			
			% NOTE: selection updates the sound info control as well as filters
			% the log control contents
			
			case 'Show Files ...'
				
				%--
				% get string value from associated control
				%--
				
				g = findobj(pal, 'tag', 'Sounds', 'style', 'listbox');

				L = get(g, 'string'); ix = get(g, 'value'); 
				
				% NOTE: return if there is no selection
				
				if isempty(ix)
					return;
				end
				
				if (length(ix) == 1)
					value = {L{ix}};
				else
					for k = 1:length(ix)
						value{k} = L{ix(k)};
					end
				end
								
				%--
				% get sounds in library
				%--
				
				sounds = get_library_sounds;
				
				names = sound_name(sounds);
				
				%--
				% match sound and open directory containing files
				%--
				
				for k = 1:length(value)

					ix = find(strcmp(value{k}, names))
					
					if ~isempty(ix)
						
						if strcmpi(sounds(ix).type, 'file')
							file = [sounds(ix).path, sounds(ix).file];
						else
							file = sounds(ix).path;
						end
						
						show_file(file);
						
					end
					
				end
			
			%------------------------------------------------------------------
			% DELETE ...
			%------------------------------------------------------------------
					
			case 'Delete ...'
				
				delete_sounds(pal);

			%------------------------------------------------------------------
			% SELECTION
			%------------------------------------------------------------------
			
			% selection updates the sound info control as well as filters
			% the log control contents
			
			otherwise				
				
				%--
				% get selected sounds in sounds control
				%--
				
				value = get(obj,'string'); ix = get(obj,'value'); nix = length(ix);
				
				sound_names = {value{ix}};
					
				%--
				% open sound on double click
				%--

				% NOTE: does the open action here avoid focus returning to palette?

				if double_click(obj) && nix == 1
					
					open_library_sound(sound_names); return;
					
				end
	
				%--
				% get sounds
				%--

				sounds = get_library_sounds([], 'name', sound_names);

				%-------------------------
				% UPDATE SOUNDS
				%-------------------------

				S = sound_info_str(sounds);

				%--
				% update sound info
				%--

				g = findobj(pal,'tag','sound_info','style','listbox');

				set(g, ...
					'string',S, ...
					'value',[], ...
					'listboxtop',1, ...
					'enable','on' ...
				);

				%--
				% update find logs
				%--

				g = findobj(pal,'tag','find_logs','style','edit'); set(g,'string','');
				
				xbat_controls_callback(g);

				%-------------------------
				% UPDATE CONTEXT MENUS
				%-------------------------
				
				update_context_menus(pal);
				
		end
		
	%------------------------------------------------------------------
	% ADD FILE
	%------------------------------------------------------------------
	
	% creation of a library does not at the moment make it the current
	% library, this behavior may be reconsidered.
		
	case 'Add File ...'
		
		%--
		% create single file sound
		%--
		
		sounds = sound_create('File');
				
		if isempty(sounds)
			return;
		end
		
		%--
		% add sound to library
		%--

		add_sounds(sounds);
		
		%--
		% update palette
		%--
		
		g = findobj(pal,'tag','Library','style','popupmenu');
		
		xbat_controls_callback(g,[]);
			
		%-------------------------
		% UPDATE CONTEXT MENUS
		%-------------------------
		
		update_context_menus(pal)
		
	%------------------------------------------------------------------
	% ADD FOLDER
	%------------------------------------------------------------------
	
	% NOTE: library creation does not make it the current library, reconsider this 
		
	case 'Add Folder ...'
		
		p = get_env('xbat_sound_data_path'); 
		
		if isempty(p) || ~exist(p,'dir')
			p = set_env('xbat_sound_data_path', pwd);
		end
		
		%------------------------------------------------------------------
		% get library root directory
		%------------------------------------------------------------------
		
		p = uigetdir(p, 'Select directory containing sound files');
	
		if p
			
			%--
			% consider filesep at the end of the drive selection
			%--
			
			if (p(end) == filesep)
				p = p(1:end - 1);
			end
			
			set_env('xbat_sound_data_path', p);
			
			%--
			% get sounds in folder and add them to the library
			%--
			
			lib = get_active_library;
			
			sounds = get_folder_sounds(p, 1, {@add_sounds, lib, 0});
			
			%--
			% update cache
			%--
			
			get_library_sounds(lib, 'refresh');

			%--
			% update palette
			%--
			
			g = findobj(pal, 'tag', 'Library', 'style', 'popupmenu');
			
			xbat_controls_callback(g, []);
			
		end
		
		%-------------------------
		% UPDATE CONTEXT MENUS
		%-------------------------
		
		update_context_menus(pal)
		
	case 'Acquire ...'
		
		sound = sound_create('recording');
		
		add_sounds(sound);
		
		%--
		% update palette
		%--
		
		g = findobj(pal,'tag','Library','style','popupmenu');
		
		xbat_controls_callback(g,[]);
		
		%-------------------------
		% UPDATE CONTEXT MENUS
		%-------------------------
		
		update_context_menus(pal);
		
	%------------------------------------------------------------------
	% FIND LOGS
	%------------------------------------------------------------------
	
	case 'find_logs'
		
		%------------------------------------------------------------------
		% FILTER AVAILABLE LOGS
		%------------------------------------------------------------------
		
		%--
		% get pattern
		%--
		
		pat = get(obj, 'string');
		
		%--
		% get filtered sounds
		%--
		
		g = findobj(pal,'tag','Sounds','style','listbox');
		
		sounds = get(g,'string');
		
		ix = get(g,'value');
		if ~isempty(ix)
			sounds = sounds(get(g,'value'));
		end
		
		%--
		% get available library logs and filter using pattern
		%--
	
		logs = filter_strings(get_library_logs('info', [], sounds), pat);
		
		%--
		% update log control
		%--
		
		g = findobj(pal,'tag','Logs','style','listbox');
		
		if isempty(logs)
			set(g, ...
				'string',{'(No Logs Found)'}, ...
				'value',[], ...
				'listboxtop',1, ...
				'enable','off' ...
			);
		else
			set(g, ...
				'string',logs, ...
				'value',[], ...
				'listboxtop',1, ...
				'enable','on' ...
			);
		end
		
		% also update logs label
		
% 		logs = get_library_logs('logs', [], sounds);
		
		g = findobj(pal, 'tag', 'Logs', 'style', 'text');

		set(g,'string',['Logs  (', integer_unit_string(length(logs), 'log'), ')']);		
		
		%--
		% update log info
		%--
		
		g = findobj(pal,'tag','log_info','style','listbox');
		
		set(g, ...
			'string',[], ...
			'listboxtop',1, ...
			'value',[] ...
		);
		
		%--
		% update log info if appropiate
		%--
		
		if (length(logs) == 1)
			
			g = findobj(pal,'tag','Logs','style','listbox');
			
			set(g, ...
				'value',1, ...
				'listboxtop',1 ...
			);
			
			xbat_controls_callback(g);
			
		end
		
		%-------------------------
		% UPDATE CONTEXT MENUS
		%-------------------------
		
		update_context_menus(pal);
		
	%------------------------------------------------------------------
	% LOGS ACTIONS
	%------------------------------------------------------------------
	
	case ('Logs')
				
		switch (action)
			
			%------------------------------------------------------------------
			% OPEN
			%------------------------------------------------------------------
			
			% open checks for windows that may currently be browsing the
			% parent sound and opens the logs in these, otherwise a new
			% sound browser is opened that displays the sound at the point
			% where the log was last closed
			
			case ({'Open','Open in New Window'})
								
				%--
				% get string value from associated control
				%--
				
				g = findobj(pal,'tag','Logs','style','listbox');

				L = get(g,'string');
				ix = get(g,'value'); 
				
				% return if there is no selection
				
				if (isempty(ix))
					return;
				end
				
				if (length(ix) == 1)
					value = {L{ix}};
				else
					for k = 1:length(ix)
						value{k} = L{ix(k)};
					end
				end
								
				%--
				% open logs
				%--
				
				% set open in new window option
				
				if (strcmp(action,'Open'))
					opt = 0;
				else
					opt = 1;
				end
				
				% open selected logs in proper mode
				
				for k = 1:length(value)
					open_log(value{k},opt);
				end
				
			%------------------------------------------------------------------
			% DELETE
			%------------------------------------------------------------------
			
			case('Export Clips ...')
				
				%--
				% get logs to export from parent control value
				%--
				
				[ignore,value] = control_update([],pal,tag);
		
				%--
				% ask for output directory
				%--
				
				top_dir = uigetdir;

				if (~top_dir)
					return;
				end
				
				%--
				% build log file names
				%--
				
				lib_path = get_field(get_active_library,'path');
				
				for k = 1:length(value)		
					log_file{k} = [lib_path, strrep(value{k},filesep,[filesep 'Logs' filesep]), '.mat'];
				end
				
				%--
				% configure export log
				%--
				
				opt = export_log;
				
				opt.image.create = 1;
				
				%--
				% load logs and export
				%--
				
				% NOTE: consider using a waitbar display for the collection
				
				for k = 1:length(log_file)
					
					%--
					% load log from file
					%--
					
					% NOTE: the use of the structure fieldname is cumbersome
					
					tmp = load(log_file{k});
					
					name = fieldnames(tmp);
					
					log = tmp.(name{1});
					
					%--
					% export log
					%--
					
					export_log(log,opt,top_dir);
					
				end
						
			%------------------------------------------------------------------
			% DELETE
			%------------------------------------------------------------------
					
			case ('Delete ...')
				
				delete_logs(pal);
								
			%------------------------------------------------------------------
			% SHOW FILES ...
			%------------------------------------------------------------------
			
			% selection updates the sound info control as well as filters
			% the log control contents
			
			case ('Show Files ...')
				
				%--
				% get string value from associated control
				%--
				
				g = findobj(pal,'tag','Logs','style','listbox');

				L = get(g,'string');
				ix = get(g,'value'); 
				
				if (isempty(ix))
					return;
				end
				
				if (length(ix) == 1)
					value = {L{ix}};
				else
					for k = 1:length(ix)
						value{k} = L{ix(k)};
					end
				end
				
				%--
				% group same sound files into groups
				%--
				
				% this code assumes that the strings are ordered into groups
				
				tok = '';
								
				for k = length(value):-1:1
										
					[new_tok,str] = strtok(value{k},filesep);
					
					if (~strcmp(new_tok,tok))
						tok = new_tok;
					else
						value(k) = [];
					end
					
				end
				
				%--
				% show files
				%--
				
				% check that we are in windows. find the unix alternative
				
				% the last file in each group is selected
				
				lib = get_active_library;
				
				for k = 1:length(value)
					
					file = [lib.path , strrep(value{k}, filesep, [filesep, 'Logs', filesep]), '.mat'];
					
					show_file(file);
					
				end
										
			%------------------------------------------------------------------
			% SELECTION
			%------------------------------------------------------------------
			
			% selection in the logs control updates the log info control
			
			otherwise
				
				%--
				% get selected logs in logs control
				%--
				
				value = get(obj,'string');
				
				ix = get(obj,'value');
				
				%--
				% set and check timer to trigger double click action
				%--
					
				flag = double_click(obj);
				
				%--
				% handle the update with multiple logs selected
				%--
				
				if (length(ix) > 1)
					
					%-------------------------
					% UPDATE LOGS
					%-------------------------
					
					%--
					% update log info
					%--
					
					g = findobj(pal,'tag','log_info','style','listbox');
					
					set(g, ...
						'string',[], ...
						'value',[], ...
						'listboxtop',1, ...
						'enable','off' ...
					);
					
					%-------------------------
					% UPDATE CONTEXT MENUS
					%-------------------------
					
					update_context_menus(pal);
					
					return;
					
				end
				
				%--
				% handle the update with single log selected
				%--
				
				value = value{ix};
				
				%--
				% open log file
				%--
				
				p = get_field(get_active_library,'path');
				
				str = [p strrep(value,filesep,[filesep 'Logs' filesep]) '.mat'];
				
% 				ptr = get(pal,'pointer'); % change pointer to indicate opening of file
% 				
% 				set(pal,'pointer','watch');
				
				f = open(str);
				
% 				set(pal,'pointer',ptr);
				
				name = fieldnames(f);
				
				f = f.(name{1});
					
				%-------------------------
				% UPDATE LOGS
				%-------------------------
								
				%--
				% create log info string 
				%--

				S = log_info_str(f);
						
				%--
				% update log info control
				%--
				
				g = findobj(pal,'tag','log_info','style','listbox');
				
				set(g, ...
					'string',S, ...
					'value',[], ...
					'listboxtop',1, ...
					'enable','on' ...
				);
				
				%--
				% open log based on double click
				%--
				
				if (flag)
					open_log(value); % this is equivalent to open log
				end
				
				%-------------------------
				% UPDATE CONTEXT MENUS
				%-------------------------
				
				update_context_menus(pal);
				
		end
				
end


%-------------------------------------------------------------------------
% OPEN_LOG
%-------------------------------------------------------------------------

function open_log(value, opt)

% open_log - handle opening logs from palette
% -------------------------------------------
%
% open_log(value, opt)
%
% Input:
% ------
%  value - string indicating log to open (from listbox)
%  opt - option to open in new window (def: 0)

%--
% set new window option
%--

if (nargin < 2) || isempty(opt)
	opt = 0;
end

%--
% convert the listbox naming convention
%--

value = strrep(value, filesep, [filesep, 'Logs', filesep]);

%--
% get log from file
%--

p = get_field(get_active_library, 'path');

log_file = [p, value, '.mat'];

tmp = open(log_file);

name = fieldnames(tmp);

log = tmp.(name{1});

%--
% check whether log is already open
%--

[g,h] = log_is_open(log);

if ~isempty(g)
	
	%--
	% bring figure to front
	%--
	
	% perhaps also make visible and redisplay or
	% something along those lines
	
	figure(g); return;
	
else
	
	%--
	% try to open log in an existing window
	%--
	
	if (~isempty(h) & ~opt)
		
		%--
		% check whether parent sound is already open
		%--
				
		name = sound_name(log.sound);
	
		for k = 1:length(h)
			
			%--
			% get sound open information from figure tag
			%--
			
			info = parse_tag(get(h(k),'tag'));
			
			%--
			% open log if sound names match
			%--
			
			if (strcmp(name,info.sound))
				
				log_open(h(k),log_file);
				
				return;
				
			end
			
		end
		
	end
		
	%--
	% open log sound in browser
	%--
	
	% this makes sure that the log looks as it did when the log was
	% closed
	
	tmp = browser(log.sound);
	
	%--
	% open log in sound browser
	%--
	
	log_open(tmp,log_file);
	
	%--
	% set browser pointer to arrow
	%--
	
	% this should not be needed and runs the risk of erasing any state
	% stored in the pointer (in the future), however the current effect of
	% the pointer remaining as watch is worse.
	
	set(tmp,'pointer','arrow');
		
end

%---------------------------
% UPDATE_CONTEXT_MENUS
%---------------------------

function update_context_menus(pal)

%--
% update sounds
%--

g = findobj(pal,'tag','Sounds','style','listbox');
		
if (isempty(get(g,'value')))
	state = 'off';
else
	state = 'on';
end

set(get(get(g,'uicontextmenu'),'children'),'enable',state);

%--
% update logs
%--

g = findobj(pal,'tag','Logs','style','listbox');

if (isempty(get(g,'value')))
	state = 'off';
else
	state = 'on';
end

set(get(get(g,'uicontextmenu'),'children'),'enable',state);
		

%------------------------------------------------------------
% COPY TO LIBRARY
%------------------------------------------------------------

function copy_to_library(obj,eventdata)

%--
% get path of library to copy to
%--

[name, usr] = parse_libname(get(obj,'label'));

if isempty(usr)
	usr = get_active_user; usr = usr.name;
end

dest = get_libraries(get_users('name', usr),'name',name);

%--
% get active library and sounds to copy
%--

src = get_active_library;

g = findobj(gcf,'tag','Sounds','style','listbox');

sounds = get(g,'string');

sounds = sounds(get(g,'value'));

%--
% copy sound directories
%--

% add check for the existence of the sounds in the destination library and
% indicate that this is the case, thus there are two type of warnings
% issued

%--
% create waitbar
%--

%-------------------------------------------
% WAITBAR CODE
%-------------------------------------------
	
h = wait_bar(0);
	
set(h,'name','XBAT > Copy to Library');
	
n = length(sounds);

for k = 1:n
	
	%--
	% check that sound exists
	%--
	
	if (exist([dest.path sounds{k}],'dir'))
		flag(k) = 2;
	else
		flag(k) = copyfile([src.path sounds{k}],[dest.path sounds{k}]);
	end
		
	%--
	% display confirmation
	%--
	
	%-------------------------------------------
	% WAITBAR CODE
	%-------------------------------------------
	
	switch (flag(k))
		
		case (0)
			wait_bar(k/n,h,['Failed to copy ''' sounds{k} ''' to ''' name '.']);
			
		case (1)
			wait_bar(k/n,h,['''' sounds{k} ''' copied to ''' name '''']);
			
		case (2)
			wait_bar(k/n,h,['''' sounds{k} ''' already exists in ''' name '''']);
			
	end
	
	pause(0.1);
	
end

%--
% report results and delete waitbar
%--

%-------------------------------------------
% WAITBAR CODE
%-------------------------------------------

m = sum(flag == 1);

wait_bar(1,h,[int2str(m) ' sounds copied to ''' name ''' library']);

pause(1);

delete(h);

get_library_sounds(dest,'refresh');


% this code tests the idea of having a single button that serves as both
% cancel and confirm using the keypress function, in principle the user
% presses a key before pressing the button providing the button and the
% corresponding callback function some context information. the operation
% performed by the button upon pressing is indicated by the changing icon
% (in this case text) on the button 'X' for cancel and '+' for confirm


function xbat_palette_kpfun(obj,eventdata)

% %--
% % code to display codes available
% %--
% 
% disp('-----------------------');
% key = get(gcf,'currentkey')
% chr = get(gcf,'currentcharacter')
% code = double(chr)

% %--
% % code to toggle the button appearing during edit
% %--
% 
% % g = findobj(gcf,'tag','New User Cancel')
% % 
% % if (~isempty(g))
% % 	
% % 	if (strcmp(key,'shift'))	
% % 		set(g,'string','X','fontsize',7,'fontname','Comic Sans MS');	
% % 	else
% % 		set(g,'string','+','fontsize',10,'fontname','Courier New');
% % 	end
% % 	
% % end

%-------------------------------------------------------------------------
% DELETE_LOGS
%-------------------------------------------------------------------------

function delete_logs(pal)

% delete_logs - callback for delete logs
% ----------------------------------------
%
% delete_logs(pal)
%
% Input:
% ------
%  pal - XBAT palette figure handle

%-------------------------------------------
% get names of logs to delete
%-------------------------------------------

%--
% try to get string value from associated control
%--

g = findobj(pal,'tag','Logs','style','listbox');

L = get(g,'string');
ix = get(g,'value');

% return if there is no selection

if isempty(ix)
	return;
end

% make sure that value is in a cell array

if length(ix) == 1
	value = {L{ix}};
else
	for k = 1:length(ix)
		value{k} = L{ix(k)};
	end
end
								
%-------------------------------------------
% create waitbar
%-------------------------------------------

%--
% progress waitbar
%--

control = control_create( ...
	'name','PROGRESS', ...
	'alias','Deleting Logs ...', ...
	'style','waitbar', ...
	'confirm',1, ...
	'lines',1.15, ...
	'space',0.5 ...
);

name = ['Delete Logs ...'];

h = waitbar_group(name, control);

%-------------------------------------------
% delete logs
%-------------------------------------------

lib = get_active_library;

lib_path = get_field(lib,'path');
			
n = length(value);

for k = 1:n
	
	%--
	% load log from file
	%--
	
	log_file = [lib_path strrep(value{k},filesep,[filesep 'Logs' filesep]) '.mat'];
	
	log = load(log_file);
	field = fieldnames(log);
	
	log = log.(field{1});
	
	%--
	% check whether log is open
	%--
	
	test = log_is_open(log);
	
	%--
	% try to delete log file if not open
	%--
	
	if ~isempty(test)
		
		flag(k) = 2;
		
	else
		
		flag(k) = 1;
		
		% backup log and delete (the backup may not be needed since the log
		% is backed up when it's closed !!! leave on for the moment
		
		log_backup(log);
		
		delete(log_file);
		
	end
						
	%--
	% display confirmation
	%--
	
	%-------------------------------------------
	% WAITBAR CODE
	%-------------------------------------------

	switch flag(k)
		
		% log file removed (assume this does not fail)
		
		case (1)
			waitbar_update(h,'PROGRESS', ...
				'value',k/n, ...
				'message',['''' value{k} ''' was deleted'] ...
			);
			
		% log is open
		
		case (2)
			waitbar_update(h,'PROGRESS', ...
				'value',k/n, ...
				'message',['''' value{k} ''' is open and was not deleted'] ...
			);
			
	end
		
end

%--
% update library display
%--

% g = findobj(pal,'tag','find_sounds','style','listbox');

xbat_palette('find_sounds');

%--
% report results and delete waitbar
%--

%-------------------------------------------
% WAITBAR CODE
%-------------------------------------------

m = sum(flag == 1);

waitbar_update(h,'PROGRESS', ...
	'value', 1, ...
	'message', [int2str(m), ' logs deleted from ''', lib.name, ''' library'] ...
);

delete(h);

%--------------------------------------------
% DELETE SOUNDS
%--------------------------------------------

% TODO: factor deletion part to the same place as 'add_sounds'

function delete_sounds(pal)

% delete_sounds - callback for delete sounds
% ------------------------------------------
%
% delete_sounds(pal)
%
% Input:
% ------
%  pal - XBAT palette figure handle


%-------------------------------------------
% get names of sounds to delete
%-------------------------------------------

%--
% try to get string value from associated control
%--

g = findobj(pal,'tag','Sounds','style','listbox');

L = get(g,'string'); ix = get(g,'value');

%--
% return if there is no selection
%--

% this should not happen

if isempty(ix)
	return;
end

%--
% make sure that value is in a cell array
%--

if (length(ix) == 1)
	value = {L{ix}};
else
	for k = 1:length(ix)
		value{k} = L{ix(k)};
	end
end

%-------------------------------------------
% create waitbar
%-------------------------------------------

%--
% progress waitbar
%--

control = control_create( ...
	'name', 'PROGRESS', ...
	'alias', 'Deleting Sounds ...', ...
	'style', 'waitbar', ...
	'confirm', 1, ...
	'lines', 1.15, ...
	'space', 0.5 ...
);

name = ['Deleting Sounds ...'];

h = waitbar_group(name, control);

%-------------------------------------------
% delete sounds
%-------------------------------------------

lib = get_active_library;

lib_path = get_field(lib, 'path');

n = length(value);

for k = 1:n

	[is_open, par] = sound_is_open(value{k});
	
	if par
		close(par)
	end	
	
	%--
	% backup sound and remove
	%--
	
	sound_backup(lib, value{k});
	
	flag(k) = rmdir([lib_path, value{k}], 's'); % note that the 's' option removes non-empty directories
	
	%--
	% update waitbar
	%--

	if (flag(k) == 1)
		waitbar_update(h, 'PROGRESS', ...
			'value', k/n, ...
			'message', ['''' value{k} ''' removed from ''' lib.name ''''] ...
		);
	else
		waitbar_update(h,'PROGRESS', ...
			'value', k/n, ...
			'message', ['Failed to remove ''', value{k}, ''' from ''', lib.name, ''''] ...
		);
	end
		
end

%--
% update library cache
%--

get_library_sounds(lib, 'refresh');

%--
% update library display
%--

handles = get_control(pal, 'Library', 'handles');

xbat_controls_callback(handles.uicontrol.popupmenu, []);

%--
% update waitbar to report results and delete waitbar
%--

m = sum(flag == 1);

waitbar_update(h, 'PROGRESS', ...
	'value', 1, ...
	'message', [int2str(m), ' sounds deleted from ''', lib.name, ''' library'] ...
);

pause(0.5);

delete(h);
