class EL_BATCH_PROCESSING_DIALOG

(source code)

description

Batch processing dialog

note
	description: "Batch processing dialog"

	author: "Finnian Reilly"
	copyright: "Copyright (c) 2001-2022 Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com"

	license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
	date: "2022-12-04 16:43:12 GMT (Sunday 4th December 2022)"
	revision: "10"

deferred class
	EL_BATCH_PROCESSING_DIALOG [G]

inherit
	EL_WEL_MAIN_DIALOG
		redefine
			on_menu_command, on_control_id_command, on_paint,
			notify, activate, terminate
		end

	EL_EVENT_LISTENER
		rename
			notify as on_file_processed
		end

	WEL_EN_CONSTANTS
		export
			{NONE} all
		end

	WEL_IDC_CONSTANTS
		export
			{NONE} all
		end

	WEL_UNIT_CONVERSION
		export
			{NONE} all
		end

	EL_MODULE_LOG

	EL_MODULE_LOG_MANAGER

	EL_MODULE_DIRECTORY

	EL_MODULE_EXECUTION_ENVIRONMENT

	EL_SHARED_THREAD_MANAGER

feature {NONE} -- Initialization

	make (a_wild_card: READABLE_STRING_GENERAL)
			-- Make the main window

		do
			wild_card := a_wild_card
			make_by_id (Id_main_dialog)
			create output_dir_edit.make_by_id (Current, id_edit_output_directory)
			create input_dir_edit.make_by_id (Current, id_edit_input_directory)
			create process_files_button.make_by_id (Current, Cmd_process_files)
			create cancel_button.make_by_id (Current, Cmd_cancel)

			system_color_window_cell.put (white_brush.color)

			create timer.make
			create directory_content_processor.make_default

			create file_processed_event_proxy.make (Current)
			make_processing_thread

			create request_processing_queue.make (10)
			request_processing_queue.attach_consumer (processing_thread)
			thread_manager.extend (processing_thread)
		end

	make_processing_thread
			--
		deferred
		end

feature {NONE} -- Behaviours

	on_directory_select_input
		do
			open_input_dir_dialog.activate (Current)
			if open_input_dir_dialog.selected then
				input_dir_edit.set_text (open_input_dir_dialog.folder_name)
			end
		end

	on_directory_select_output
		do
			open_ouput_dir_dialog.activate (Current)
			if open_ouput_dir_dialog.selected then
				output_dir_edit.set_text (open_ouput_dir_dialog.folder_name)
			end
		end

	on_control_id_command (an_id: INTEGER)
			--
		do

			if an_id = Cmd_directory_browse_output then
				on_directory_select_output

			elseif an_id = Cmd_directory_browse_input then
				on_directory_select_input

			elseif an_id = Cmd_process_files then
				on_process_files

			elseif an_id = Cmd_cancel then
				on_cancel_processing

			end
		end

	on_menu_command (id_menu: INTEGER)
			--
		local
			about: WEL_MODAL_DIALOG
		do

			if id_menu = Cmd_exit then
					terminate (Idok)

			elseif id_menu = Cmd_help_about then
				create about.make_by_id (Current, Id_about_dialog)
				about.activate

			end
		end

	on_paint (paint_dc: WEL_PAINT_DC; invalid_rect: WEL_RECT)
			-- Draw the ISE logo bitmap
		do
			paint_dc.draw_bitmap (
				logo,
				cancel_button.x + cancel_button.width + 20,
				cancel_button.y - 10,
				logo.width, logo.height
			)
		end

	on_process_files
			--
		do
			log.enter ("on_process_files")
			if file_exists (input_dir_edit.text)
				and then not is_processing
			then

				create pointer_cursor.make_by_predefined_id (Idc_wait)
				pointer_cursor.set
				set_processing_thread_parameters

				files_to_process := 0
				files_processed := 0
				directory_content_processor.set_input_dir (input_dir_edit.text)
				directory_content_processor.set_output_dir (output_dir_edit.text)

				timer.start
				directory_content_processor.do_all (agent queue_file_for_processing, wild_card)
				cancel_button.enable
				is_processing := true
				is_cancelled := false
				on_file_processed
			end
			log.exit
		end

	on_file_processed
			--
		local
			button_text: STRING
		do
			log.enter ("on_file_processed")
			files_processed := files_processed + 1

			log.put_string ("Processing ")
			log.put_integer (files_processed)
			log.put_string (" of ")
			log.put_integer (files_to_process)
			log.put_new_line

			if files_processed > files_to_process then
				on_process_complete
			else
				create button_text.make_from_string ("Processing ")
				button_text.append_integer (files_processed)
				button_text.append (" of ")
				button_text.append_integer (files_to_process)
				process_files_button.set_text (button_text)
			end
			log.exit
		end

	on_process_complete
			--
		local
			msg_box: WEL_MSG_BOX; msg_title: STRING
		do
			process_files_button.set_text (process_files_button_text)
			cancel_button.disable
			pointer_cursor.restore_previous
			is_processing := false
			timer.stop
			create msg_box.make
			if is_cancelled then
				msg_title := "BATCH CANCELLED"
			else
				msg_title := "BATCH COMPLETED"
			end
			msg_box.information_message_box (Current, "Processing time: " + timer.elapsed_time.out_mins_and_secs, msg_title)
		end

	on_cancel_processing
			--
		do
			files_processed := files_to_process
			process_files_button.set_text ("Cancelling..")
			cancel_button.disable
			is_cancelled := true
			request_processing_queue.wipe_out
		end

	notify (a_control: WEL_CONTROL; notify_code: INTEGER)
			--
		do
			if notify_code = En_change then
				if not input_dir_edit.text.is_empty
					and then file_exists (input_dir_edit.text)
					and then not output_dir_edit.text.is_empty
				then
					process_files_button.enable
				else
					process_files_button.disable
				end
			end
		end

	activate
			-- Activate the dialog.
		do
			Precursor
			set_class_icon (create {WEL_ICON}.make_by_id (ID_ICO_APPLICATION))
			process_files_button_text := process_files_button.text
			processing_thread.launch
			move (10, 10)
		end

	terminate (a_result: INTEGER)
			--
		do
			log_manager.redirect_thread_to_console (1)
			log.enter ("terminate")
			if is_processing then
				on_cancel_processing
			end
			thread_manager.stop_all
			log.put_line ("FINISHED!")
			log.exit
			Precursor (a_result)
		end

feature {NONE} -- GUI attributes

	output_dir_edit: WEL_SINGLE_LINE_EDIT

	input_dir_edit: WEL_SINGLE_LINE_EDIT

	process_files_button: WEL_PUSH_BUTTON

	cancel_button: WEL_PUSH_BUTTON

	pointer_cursor: WEL_CURSOR

feature {NONE} -- GUI components

	open_input_dir_dialog: WEL_CHOOSE_FOLDER_DIALOG
		once
			create Result.make
			Result.set_title ("Select the input directory")
			Result.set_starting_folder (Directory.current_working)
		ensure
			result_not_void: Result /= Void
		end

	open_ouput_dir_dialog: WEL_CHOOSE_FOLDER_DIALOG
		once
			create Result.make
			Result.set_title ("Select the ouput directory")
			Result.set_starting_folder (Directory.current_working)
		ensure
			result_not_void: Result /= Void
		end

	file_menu: WEL_MENU
		once
			Result := menu.popup_menu (0)
		ensure
			result_not_void: Result /= Void
		end

feature {NONE} -- Resource IDs

	Id_main_dialog: INTEGER
			--
		deferred
		end

	Id_menu_application: INTEGER
			--
		deferred
		end

	Id_ico_application: INTEGER
			--
		deferred
		end


	Id_bmp_logo: INTEGER
			--
		deferred
		end

	Id_about_dialog: INTEGER
			--
		deferred
		end

	Id_edit_input_directory: INTEGER
			--
		deferred
		end

	Id_edit_output_directory: INTEGER
			--
		deferred
		end

	Cmd_directory_browse_input: INTEGER
			--
		deferred
		end

	Cmd_directory_browse_output: INTEGER
			--
		deferred
		end

	Cmd_process_files: INTEGER
			--
		deferred
		end

	Cmd_cancel: INTEGER
			--
		deferred
		end

	Cmd_exit: INTEGER
			--
		deferred
		end

	Cmd_help_about: INTEGER
			--
		deferred
		end

feature {NONE} -- Implementation

	queue_file_for_processing (input_file_path, output_file_path: FILE_PATH)
			--
		do
			request_processing_queue.put (process_request_item (input_file_path, output_file_path))
			files_to_process := files_to_process + 1
		end

	process_request_item (input_file_path, output_file_path: FILE_PATH): G
			--
		deferred
		end

	file_exists (filename: STRING): BOOLEAN
			-- Does `filename' exist?
		require
			filename_not_void: filename /= Void
		local
			a_file: PLAIN_TEXT_FILE
		do
			create a_file.make (filename)
			Result := a_file.exists
		end

	set_processing_thread_parameters
			--
		do
		end

feature {NONE} -- Internal attributes

	request_processing_queue: EL_THREAD_PRODUCT_QUEUE [G]

	directory_content_processor: EL_DIRECTORY_CONTENT_PROCESSOR

	process_files_button_text: STRING

	files_processed: INTEGER

	files_to_process: INTEGER

	is_processing: BOOLEAN

	is_cancelled: BOOLEAN

	timer: EL_EXECUTION_TIMER

	file_processed_event_proxy: EL_EVENT_LISTENER_MAIN_THREAD_PROXY
		-- Triggers notifications in main GUI thread

	processing_thread: EL_CONSUMER_THREAD [G]

	wild_card: READABLE_STRING_GENERAL

feature {NONE} -- Constants

	Logo: WEL_BITMAP
			-- ISE logo bitmap
		once
			create Result.make_by_id (Id_bmp_logo)
		end

	White_brush: WEL_WHITE_BRUSH
			-- White background
		once
			create Result.make
		end

end