note
	description: "Command to create a new project"
	legal: "See notice at end of class."
	status: "See notice at end of class."
	author: "Arnaud PICHERY [aranud@mail.dotcom.fr]"
	revised_by: "Alexander Kogtenkov"
	date: "$Date$"
	revision: "$Revision$"

class
	EB_CREATE_PROJECT_DIALOG

inherit
	EB_DIALOG

	EB_SHARED_PREFERENCES
		undefine
			default_create, copy
		end

	EXCEPTIONS
		rename
			raise as raise_exception
		export
			{NONE} all
		undefine
			default_create, copy
		end

	EB_GRAPHICAL_ERROR_MANAGER
		export
			{NONE} all
		undefine
			default_create, copy
		end

	EB_SHARED_WINDOW_MANAGER
		export
			{NONE} all
		undefine
			default_create, copy
		end

	SHARED_EIFFEL_PROJECT
		export
			{NONE} all
		undefine
			default_create, copy
		end

	EB_COMMAND_EXECUTOR
		rename
			execute as launch_ebench,
			project_location as compiler_project_location
		export
			{NONE} all
		undefine
			default_create, copy
		end

	SYSTEM_CONSTANTS
		export
			{NONE} all
		undefine
			default_create, copy
		end

	EB_CONSTANTS
		export
			{NONE} all
		undefine
			default_create, copy
		end

	EB_FILE_DIALOG_CONSTANTS
		export
			{NONE} all
		undefine
			default_create, copy
		end

	EIFFEL_LAYOUT
		export
			{NONE} all
		undefine
			default_create, copy
		end

create
	make_blank,
	make_with_ace

feature {NONE} -- Initialization

	make_blank (a_parent_window: EV_WINDOW)
			-- Create a new blank project
			--
			-- Note:
			--  + The ace file will be automatically generated
			--  + The user has to choose the project directory.
		require
			valid_parent_window: a_parent_window /= Void
		do
			parent_window := a_parent_window
			compile_project := True
			suggested_directory_name := create_default_directory_name (Default_project_name)

			ask_for_system_name := True
			blank_project_creation := True
			build_interface
			set_title (Interface_names.t_Choose_project_and_directory)
		end

	make_with_ace (a_parent_window: EV_WINDOW; ace_name: PATH; a_suggested_directory_name: PATH)
			-- Create a new project using the ace file named `ace_name'.
			-- and the suggested project directory `dir_name'.
			--
			-- Note:
			--  The user has to choose the project directory.
			--  suggested_directory_name can be set to Void to indicate
			--  no suggested directory.
		require
			valid_parent_window: a_parent_window /= Void
		do
			parent_window := a_parent_window
			ace_file_name := ace_name
			if not a_suggested_directory_name.is_empty then
				suggested_directory_name := a_suggested_directory_name
			else
				suggested_directory_name := create_default_directory_name (Default_project_name)
			end
			compile_project := True

			ask_for_system_name := False
			build_interface
			set_title (Interface_names.t_Choose_directory)
		end

feature -- Access

	compile_project: BOOLEAN
			-- Should the generated project be compiled?

	success: BOOLEAN
			-- Was last operation sucessful?

	project_location: PATH
			-- Location for selected project
		require
			success: success
		do
			create Result.make_from_string (directory_field.text)
		ensure
			project_location_not_void: Result /= Void
		end

feature -- Execution

	show_modal_to_parent
			-- Show `Current' modal to `parent_window' provided in creation procedure.
		do
			show_modal_to_window (parent_window)
		end

	create_blank_project
			-- Create a blank project in directory `directory_name'.
		local
			blank_project_builder: BLANK_PROJECT_BUILDER
			retried: BOOLEAN
			cla, clu, f: STRING_32
			sc: EIFFEL_SYNTAX_CHECKER
			l_project_loader: EB_GRAPHICAL_PROJECT_LOADER
			l_project_initialized: BOOLEAN
		do
			success := False
			if not retried then
				create sc
					-- Retrieve System parameters
				if directory_field.text = Void or else directory_field.text.is_empty then
					add_error_message (Warning_messages.w_fill_in_location_field)
					raise_exception (Invalid_directory_exception)
				end
				create directory_name.make_from_string (directory_field.text)
				check_and_create_directory (directory_name)

				system_name := system_name_field.text
				if not sc.is_valid_system_name (system_name) then
					add_error_message (Warning_messages.w_fill_in_project_name_field)
					raise_exception (Invalid_project_name_exception)
				end
				cla := root_class_field.text
				cla.to_upper
				if not sc.is_valid_class_type_name (cla) then
					add_error_message (Warning_messages.w_invalid_class_name (cla))
					raise_exception (Invalid_project_name_exception)
				end
				clu := root_cluster_field.text
				clu.to_lower
				if not sc.is_valid_group_name (clu) then
					add_error_message (Warning_messages.w_invalid_cluster_name (clu))
					raise_exception (Invalid_project_name_exception)
				end
				f := root_feature_field.text
				f.to_lower
				if not sc.is_valid_identifier (f) then
					add_error_message (Warning_messages.w_invalid_feature_name (f))
					raise_exception (Invalid_project_name_exception)
				end

				create blank_project_builder.make (system_name, cla, clu, f, directory_name, scoop_check_button.is_selected)
				ace_file_name := blank_project_builder.ace_filename
				compile_project := compile_project_check_button.is_selected

				if (create {PLAIN_TEXT_FILE}.make_with_path (ace_file_name)).exists then
						-- Warn that the existing configuration file will be overwritten.
					prompts.show_warning_prompt_with_cancel (
						warning_messages.w_file_exists (ace_file_name.name),
						Current,
						agent do success := True end,
						Void
					)
				else
					success := True
				end

				if success then
						-- Project creation can still fail
					success := False
						-- Generate the files (ace file + root class)
					blank_project_builder.create_blank_project

						-- Create a new project using the previously generated files.
					create l_project_loader.make (Current)
					l_project_loader.set_is_project_location_requested (False)
					l_project_initialized := eiffel_project.initialized
					if l_project_initialized then
						l_project_loader.enable_project_creation_or_opening_not_requested
					end
					l_project_loader.open_project_file (ace_file_name, Void, directory_name, True, Void)
					if not l_project_loader.has_error then
						if compile_project then
							l_project_loader.set_is_compilation_requested (True)
							l_project_loader.melt_project (l_project_initialized)
						elseif l_project_initialized and l_project_loader.is_project_ok then
								-- Open a new EiffelStudio session for sure since current
								-- system is already initialized.
							l_project_loader.open_project (True)
						end
					end

						-- Update `success' state.
					success := not l_project_loader.has_error and then Eiffel_project.initialized and then
						(not Eiffel_ace.file_name.is_empty)

					if success then
						if last_saved_location_checkbox.is_selected then
							preferences.dialog_data.set_last_saved_basic_project_directory (directory_name.parent)
						else
							preferences.dialog_data.set_last_saved_basic_project_directory (Void)
						end
					end

					destroy
				end
			else
				if not is_destroyed and then is_displayed then
					display_error_message (Current)
				else
					display_error_message (parent_window)
				end
			end
		rescue
			retried := True
			retry
		end

	select_project_path
			--  Select a project in directory `directory_name', with ace file
			-- `ace_file_name'.
			--
			-- Use `parent_window' as parent window when displaying dialogs
		do
			success := False
				-- If the ace file or the directory is not yet specified,
				-- retrieve it from the text field.
			if directory_field.text.is_empty then
				add_error_message (Warning_messages.w_fill_in_location_field)
				if is_displayed then
					display_error_message (Current)
				else
					display_error_message (parent_window)
				end
				success := False
			else
				compile_project := compile_project_check_button.is_selected
				success := True
			end
			destroy
		end

feature {NONE} -- Implementation

	build_interface
			-- Build the interface
		local
			vb, main_vb: EV_VERTICAL_BOX
			hb: EV_HORIZONTAL_BOX
			label: EV_LABEL
			b: EV_BUTTON
			ok_b, cancel_b: EV_BUTTON
			buttons_box: EV_HORIZONTAL_BOX
			project_directory_frame: EV_FRAME
			system_name_frame: EV_FRAME
			clal, clul, snl, fnl, scoop_label: EV_LABEL
			cb: EV_CHECK_BUTTON
			sz: INTEGER
		do
				-- Let the user choose the directory
			default_create

				-- Ask for the system name if it's not already known.
			if ask_for_system_name then
				create system_name_frame.make_with_text (Interface_names.l_System_properties)
				create main_vb
				main_vb.set_padding (Layout_constants.Tiny_padding_size)
				main_vb.set_border_width (Layout_constants.Small_border_size)
				create clal.make_with_text (Interface_names.L_root_class_name)
				create clul.make_with_text (Interface_names.L_root_cluster_name)
				create snl.make_with_text (Interface_names.L_system_name)
				create fnl.make_with_text (Interface_names.L_root_feature_name)
				create scoop_label.make_with_text (interface_names.l_concurrency)
				sz := clal.minimum_width.max
					(clul.minimum_width).max
					(snl.minimum_width).max
					(fnl.minimum_width).max
					(scoop_label.minimum_width)
				clal.set_minimum_width (sz)
				clal.align_text_left
				clul.set_minimum_width (sz)
				clul.align_text_left
				snl.set_minimum_width (sz)
				snl.align_text_left
				fnl.set_minimum_width (sz)
				fnl.align_text_left
				scoop_label.set_minimum_width (sz)
				scoop_label.align_text_left
					-- System name
				create system_name_field.make_with_text (Default_project_name)
				system_name_field.change_actions.extend (agent on_change_project_name)
				create hb
				hb.extend (snl)
				hb.disable_item_expand (snl)
				hb.extend (system_name_field)
				main_vb.extend (hb)
					-- Root cluster name
				create root_cluster_field.make_with_text (Default_root_cluster_name)
				create hb
				hb.extend (clul)
				hb.disable_item_expand (clul)
				hb.extend (root_cluster_field)
				main_vb.extend (hb)
					-- Root class name
				create root_class_field.make_with_text (Default_root_class_name)
				create hb
				hb.extend (clal)
				hb.disable_item_expand (clal)
				hb.extend (root_class_field)
				main_vb.extend (hb)
					-- Root feature name
				create root_feature_field.make_with_text (Default_root_feature_name)
				create hb
				hb.extend (fnl)
				hb.disable_item_expand (fnl)
				hb.extend (root_feature_field)
				main_vb.extend (hb)
					-- SCOOP flag
				create scoop_check_button.default_create
				create hb
				hb.extend (scoop_label)
				hb.disable_item_expand (scoop_label)
				hb.extend (scoop_check_button)
				main_vb.extend (hb)
				scoop_check_button.enable_select

				system_name_frame.extend (main_vb)
			else
					-- Ace file Name
				create label.make_with_text (ace_file_name.name)
				create system_name_frame.make_with_text (Interface_names.l_Ace_file_for_frame)
				create hb
				hb.set_border_width (layout_constants.small_border_size)
				hb.extend (label)
				hb.disable_item_expand (label)
				system_name_frame.extend (hb)
			end

				-- Project directory
			create project_directory_frame.make_with_text (Interface_names.l_location_colon)
			create vb
			vb.set_border_width (Layout_constants.Small_border_size)
			vb.set_padding (Layout_constants.Small_padding_size)

			create directory_field
			if suggested_directory_name /= Void then
				directory_field.set_text (suggested_directory_name.name)
			end
			create b.make_with_text_and_action (Interface_names.b_Browse, agent browse_directory)
			create hb
			hb.set_padding_width (Layout_constants.Small_border_size)
			hb.extend (directory_field)
			hb.extend (b)
			hb.disable_item_expand (b)
			vb.extend (hb)
			vb.disable_item_expand (hb)
			create label.make_with_text (Interface_names.l_Project_location)
			label.align_text_left
			vb.extend (label)

			if ask_for_system_name then
					-- Remember location, only for project creation.
				create cb.make_with_text (Interface_names.l_remember_project_location)
				cb.set_tooltip (Interface_names.f_remember_project_location_tooltip)
				last_saved_location_checkbox := cb
				if preferences.dialog_data.last_saved_basic_project_directory /= Void then
					cb.enable_select
				else
					cb.disable_select
				end
				vb.extend (cb)
			end

			project_directory_frame.extend (vb)

				-- "Compile project" Check box
			create compile_project_check_button.make_with_text (Interface_names.l_compile_project)
			if compile_project then
				compile_project_check_button.enable_select
			else
				compile_project_check_button.disable_select
			end

				--| Action buttons box
			create ok_b.make_with_text_and_action (Interface_names.b_OK, agent on_ok)
			Layout_constants.set_default_width_for_button (ok_b)
			create cancel_b.make_with_text_and_action (Interface_names.b_Cancel, agent on_cancel)
			Layout_constants.set_default_width_for_button (cancel_b)
			create buttons_box
			buttons_box.enable_homogeneous
			buttons_box.set_padding (Layout_constants.Small_padding_size)
			buttons_box.extend (ok_b)
			buttons_box.extend (cancel_b)
			create hb
			hb.extend (create {EV_CELL})
			hb.extend (buttons_box)
			hb.disable_item_expand (buttons_box)

				-- General layout
			create vb
			vb.set_padding (Layout_constants.Small_border_size)
			vb.set_border_width (Layout_constants.Default_border_size)
			vb.extend (system_name_frame)
			vb.disable_item_expand (system_name_frame)
			vb.extend (project_directory_frame)
			vb.disable_item_expand (project_directory_frame)
			vb.extend (compile_project_check_button)
			vb.disable_item_expand (compile_project_check_button)
			vb.extend (create {EV_CELL})
			vb.extend (hb)
			vb.disable_item_expand (hb)
			extend (vb)
			set_width (Layout_constants.Dialog_unit_to_pixels (500))

				--| Setting default buttons
			set_default_push_button (ok_b)
			set_default_cancel_button (cancel_b)

			show_actions.extend (agent on_window_shown)
		end

	on_window_shown
			-- The window has just been shown.
			-- Set the focus to the first widget and show the beginning of each text field.
		do
			if ask_for_system_name then
				system_name_field.set_caret_position (1)
				system_name_field.set_focus
			else
				if not directory_field.text.is_empty then
					directory_field.set_caret_position (1)
					directory_field.set_focus
				end
			end
		end

	browse_directory
			-- Popup a "select directory" dialog.
		local
			dd: EV_DIRECTORY_DIALOG
			start_directory: PATH
		do
			create dd
			dd.set_title (Interface_names.t_select_a_directory)
			if directory_field /= Void then
				create start_directory.make_from_string (directory_field.text)
				if not start_directory.is_empty and then (create {DIRECTORY}.make_with_path (start_directory)).exists then
					dd.set_start_path (start_directory)
				end
			end
			dd.ok_actions.extend (agent retrieve_directory (dd))
			dd.show_modal_to_window (Current)
		end

	check_and_create_directory (a_directory_name: PATH)
			-- Check that the directory `a_directory_name' is valid and exists and MODIFY IT if needed.
			-- If `a_directory_name' is not valid or does not exits, a developper exception is raised.
		local
			d: DIRECTORY
		do
				-- Try to create the directory.
			create d.make_with_path (a_directory_name)
			d.recursive_create_dir
			if not d.exists then
				raise_exception ("Cannot create a directory.")
			end
		rescue
			add_error_message (Warning_messages.w_Invalid_directory_or_cannot_be_created (a_directory_name.name))
		end

	create_default_directory_name (project_name: READABLE_STRING_GENERAL): PATH
			-- Return the proposed directory for project `project_name'
		do
			if
				attached preferences.dialog_data.last_saved_basic_project_directory as p
			then
				Result := p
			else
				Result := eiffel_layout.user_projects_path
			end
			Result := Result.extended (project_name)
		end

	old_project_name: STRING_32
			-- Old project name, set by user

feature {NONE} -- Callbacks

	on_cancel
			-- User has clicked "Cancel"
		do
			success := False
			destroy
		end

	on_ok
			-- User has clicked "Ok"
		do
			if blank_project_creation then
				create_blank_project
			else
				select_project_path
			end
		end

	on_change_project_name
			-- The user has changed the project name, update the project location
		local
			curr_project_location: STRING_32
			curr_project_name: STRING_32
			sep_index: INTEGER
		do
			curr_project_name := system_name_field.text
			curr_project_location := directory_field.text

			if old_project_name = Void or else old_project_name.is_equal (root_cluster_field.text) then
				root_cluster_field.set_text (curr_project_name)
			end
			if not curr_project_location.is_empty then
				sep_index := curr_project_location.last_index_of (Operating_environment.Directory_separator, curr_project_location.count)
				curr_project_location.keep_head (sep_index)
				if curr_project_name /= Void then
					curr_project_location.append (curr_project_name)
				end

				directory_field.set_text (curr_project_location)
			end

			old_project_name := system_name_field.text
		ensure
			old_project_name_attached: old_project_name /= Void
			old_project_name_set: old_project_name.is_equal (system_name_field.text)
		end

	retrieve_directory (dialog: EV_DIRECTORY_DIALOG)
			-- Get callback information from `dialog', then send it to the directory field.
		local
			l_dir: PATH
		do
			l_dir := dialog.path
			if l_dir.is_empty then
				prompts.show_error_prompt (Warning_messages.w_directory_not_exist (""), Current, Void)
			else
				directory_field.set_text (l_dir.name)
			end
		end

feature {NONE} -- Private attributes

	blank_project_creation: BOOLEAN
			-- Should we create a blank project when user click "OK"?

	parent_window: EV_WINDOW
			-- Parent window

	ace_file_name: PATH
			-- Name of the ace file to create the project with.

	directory_name: PATH
			-- Directory to create the project in.

	system_name: STRING_32
			-- Name of the system of the project to create.

	suggested_directory_name: detachable PATH
			-- Initial directory (suggestion, can be Void)

	ask_for_system_name: BOOLEAN
			-- Should `build_interface' be built so that it asks for
			-- the system name? (if False, ask for the ace file)

	overwrite_project_confirmation_flag: BOOLEAN
			-- Should we display a confirmation dialog before deleting
			-- the EIFGEN?

feature {NONE} -- Vision2 architechture

	directory_field: EV_TEXT_FIELD

	last_saved_location_checkbox: EV_CHECK_BUTTON

	system_name_field: EV_TEXT_FIELD

	root_class_field: EV_TEXT_FIELD

	root_cluster_field: EV_TEXT_FIELD

	root_feature_field: EV_TEXT_FIELD

	scoop_check_button: EV_CHECK_BUTTON

	compile_project_check_button: EV_CHECK_BUTTON

feature {NONE} -- Constants

	Default_project_name: STRING_32 = "project"

	Default_root_class_name: STRING = "APPLICATION"

	Default_root_feature_name: STRING = "make"

	Default_root_cluster_name: STRING = "project"

	Invalid_ace_exception: STRING = "Invalid_ace"

	Invalid_directory_exception: STRING = "Invalid_directory"

	Invalid_project_name_exception: STRING = "Invalid_project_name";

note
	copyright: "Copyright (c) 1984-2019, Eiffel Software"
	license: "GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)"
	licensing_options:	"http://www.eiffel.com/licensing"
	copying: "[
			This file is part of Eiffel Software's Eiffel Development Environment.
			
			Eiffel Software's Eiffel Development Environment 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, version 2 of the License
			(available at the URL listed under "license" above).
			
			Eiffel Software's Eiffel Development Environment 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 Eiffel Software's Eiffel Development
			Environment; if not, write to the Free Software Foundation,
			Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
		]"
	source: "[
			Eiffel Software
			5949 Hollister Ave., Goleta, CA 93117 USA
			Telephone 805-685-1006, Fax 805-685-6869
			Website http://www.eiffel.com
			Customer support http://support.eiffel.com
		]"

end