note
	description	: "Command to change links layout."
	legal: "See notice at end of class."
	status: "See notice at end of class."
	date		: "$Date$"
	revision	: "$Revision$"

class
	EB_LINK_TOOL_COMMAND

inherit
	EB_CONTEXT_DIAGRAM_COMMAND
		undefine
			menu_name
		redefine
			new_sd_toolbar_item,
			initialize
		end

	EB_CONTEXT_DIAGRAM_TOGGLE_COMMAND
		redefine
			menu_name
		end

create
	make

feature {NONE} -- Initialization

	initialize
			-- Initialize default values.
		do
			create accelerator.make_with_key_combination (
				create {EV_KEY}.make_with_code ({EV_KEY_CONSTANTS}.key_r),
				True, False, False)
			accelerator.actions.extend (agent execute)
		end

feature -- Basic operations

	execute
			-- Perform on the whole diagram.
		local
			l_all_saved_edges: like all_saved_edges
			l_world: EIFFEL_WORLD
			l_string: STRING_GENERAL
		do
			if is_sensitive then
				l_all_saved_edges := all_saved_edges
				l_world := tool.world
				if not l_world.is_right_angles then
					l_world.enable_right_angles
					l_world.apply_right_angles
					enable_select
					history.register_named_undoable (
						interface_names.t_diagram_put_right_angles_cmd,
						[<<agent l_world.enable_right_angles, agent l_world.apply_right_angles, agent enable_select>>],
						[<<agent l_world.disable_right_angles, agent undo_apply_right_angles (l_all_saved_edges), agent disable_select>>])
				else
					l_world.disable_right_angles
					l_world.remove_right_angles
					disable_select
					history.register_named_undoable (
						interface_names.t_diagram_remove_right_angles_cmd,
						[<<agent l_world.disable_right_angles, agent l_world.remove_right_angles, agent disable_select>>],
						[<<agent l_world.enable_right_angles, agent l_world.apply_right_angles, agent enable_select>>])
				end
				l_string := tooltip.twin
				l_string.append (shortcut_string.as_string_32)
				current_button.set_tooltip (l_string)
			end
		end

	execute_with_link_stone (a_stone: LINK_STONE)
			-- Change `a_stone' layout as the user wants.
		local
			lf: EIFFEL_LINK_FIGURE
			x_pos, y_pos: INTEGER
			client_stone: CLIENT_STONE
			screen: EV_SCREEN
		do
			if a_stone.source.world = tool.world then
				create link_tool_dialog
				link_tool_dialog.set_link_tool_command (Current)

					-- Save current link midpoints.
				lf := a_stone.source
				link_tool_dialog.set_link_figure (lf)
				saved_edges := lf.edges

				create screen
				x_pos := screen.pointer_position.x - link_tool_dialog.width // 2
				y_pos := screen.pointer_position.y - link_tool_dialog.height // 2
				link_tool_dialog.set_position (x_pos, y_pos)

				client_stone ?= a_stone
				if client_stone /= Void then
					link_tool_dialog.set_strings (client_stone.source.feature_names)
					link_tool_dialog.set_for_client_link
				else
						--| FIXME: `disable_user_resize' makes the development window
						--| go to the background when closing `link_tool_dialog'.
					link_tool_dialog.set_maximum_size (link_tool_dialog.width, link_tool_dialog.height)
				end

				link_tool_dialog.show_relative_to_window (tool.develop_window.window)
			end
		end

	new_sd_toolbar_item (display_text: BOOLEAN): EB_SD_COMMAND_TOOL_BAR_TOGGLE_BUTTON
			-- Create a new sd toolbar button for this command.
		do
			create Result.make (Current)
			current_button := Result
			initialize_sd_toolbar_item (Result, display_text)
			Result.select_actions.extend (agent execute)
			Result.drop_actions.extend (agent execute_with_link_stone)
		end

feature {EB_LINK_TOOL_DIALOG} -- Implementation

	on_dialog_closed
			-- The user made his mind.
		local
			lf: EIFFEL_LINK_FIGURE
			new_edges: LIST [EG_EDGE]
		do
			check
				saved_edges_not_void: saved_edges /= Void
			end
			lf := link_tool_dialog.link_figure

				-- We need to check that `lf' is still on the diagram.
			if lf.world /= Void then
				if not link_tool_dialog.cancelled then
					if not lf.is_reflexive then
						if not link_tool_dialog.reset_selected then
							lf.hide
							project
							if link_tool_dialog.handle_left_selected then
								lf.put_handle_left
							elseif link_tool_dialog.handle_right_selected then
								lf.put_handle_right
							elseif link_tool_dialog.two_handles_left_selected then
								lf.put_two_handles_left
							elseif link_tool_dialog.two_handles_right_selected then
								lf.put_two_handles_right
							end
							lf.show
							project
						end

						new_edges := lf.edges
						if link_tool_dialog.handle_left_selected then
							history.register_named_undoable (
								Interface_names.t_Diagram_put_one_handle_left_cmd,
								[<<agent lf.reset, agent lf.retrieve_edges (new_edges)>>],
								[<<agent lf.reset, agent lf.retrieve_edges (saved_edges)>>])
						elseif link_tool_dialog.handle_right_selected then
							history.register_named_undoable (
								Interface_names.t_Diagram_put_one_handle_right_cmd,
								[<<agent lf.reset, agent lf.retrieve_edges (new_edges)>>],
								[<<agent lf.reset, agent lf.retrieve_edges (saved_edges)>>])
						elseif link_tool_dialog.two_handles_left_selected then
							history.register_named_undoable (
								Interface_names.t_Diagram_put_two_handles_left_cmd,
								[<<agent lf.reset, agent lf.retrieve_edges (new_edges)>>],
								[<<agent lf.reset, agent lf.retrieve_edges (saved_edges)>>])
						elseif link_tool_dialog.two_handles_right_selected then
							history.register_named_undoable (
								Interface_names.t_Diagram_put_two_handles_right_cmd,
								[<<agent lf.reset, agent lf.retrieve_edges (new_edges)>>],
								[<<agent lf.reset, agent lf.retrieve_edges (saved_edges)>>])
						elseif link_tool_dialog.reset_selected then
							history.do_named_undoable (
								Interface_names.t_Diagram_remove_handles_cmd,
								agent lf.reset,
								agent lf.retrieve_edges (saved_edges))
						end
					end
				else
					lf.reset
					lf.retrieve_edges (saved_edges)
					project
				end
			end
			link_tool_dialog.destroy
		end

	project
			-- Call the projector.
		do
			tool.projector.project
		end

feature -- Access

	tooltip: STRING_GENERAL
			-- Tooltip for the toolbar button.
		do
			if current_button.is_selected then
				Result := Interface_names.f_diagram_remove_right_angles
			else
				Result := Interface_names.f_diagram_put_right_angles
			end
		end

feature {NONE} -- Implementation

	current_stone: LINK_STONE
			-- Last dropped stone.

	pixmap: EV_PIXMAP
			-- Pixmap representing the command.
		do
			Result := pixmaps.icon_pixmaps.diagram_force_right_angles_icon
		end

	pixel_buffer: EV_PIXEL_BUFFER
			-- Pixel buffer representing the command.
		do
			Result := pixmaps.icon_pixmaps.diagram_force_right_angles_icon_buffer
		end

	menu_name: STRING_GENERAL
			-- Name of the menu entry
		do
			Result := Interface_names.m_diagram_link_tool
		end

	name: STRING = "Link_tool"
			-- Name of the command. Used to store the command in the
			-- preferences.

	link_tool_dialog: EB_LINK_TOOL_DIALOG
			-- Associated widget.

	saved_edges: LIST [EG_EDGE]
			-- Backup of previous link midpoints.

	all_saved_edges: LIST [TUPLE [EIFFEL_LINK_FIGURE, LIST [EG_EDGE]]]
			--
		local
			l_edges: LIST [EG_LINK_FIGURE]
			l_item: EIFFEL_LINK_FIGURE
		do
			l_edges := tool.world.flat_links
			create {ARRAYED_LIST [TUPLE [EIFFEL_LINK_FIGURE, LIST [EG_EDGE]]]} Result.make (l_edges.count)
			from
				l_edges.start
			until
				l_edges.after
			loop
				l_item ?= l_edges.item
				if l_item /= Void then
					Result.extend ([l_item, l_item.edges])
				end
				l_edges.forth
			end
		ensure
			Result_not_void: Result /= Void
		end

	undo_apply_right_angles (edge_lists: like all_saved_edges)
			--
		local
			l_item: TUPLE [figure: EIFFEL_LINK_FIGURE; edges: LIST [EG_EDGE]]
			l_figure: EIFFEL_LINK_FIGURE
			l_saved_edges: LIST [EG_EDGE]
		do
			from
				edge_lists.start
			until
				edge_lists.after
			loop
				l_item := edge_lists.item
				l_figure := l_item.figure
				l_saved_edges := l_item.edges
				l_figure.reset
				l_figure.retrieve_edges (l_saved_edges)
				edge_lists.forth
			end
		end

feature {ES_DIAGRAM_TOOL_PANEL} -- Implementation

	current_button: EB_SD_COMMAND_TOOL_BAR_TOGGLE_BUTTON;
			-- Current toggle button.

note
	copyright:	"Copyright (c) 1984-2006, 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
			 356 Storke Road, Goleta, CA 93117 USA
			 Telephone 805-685-1006, Fax 805-685-6869
			 Website http://www.eiffel.com
			 Customer support http://support.eiffel.com
		]"

end -- class EB_LINK_TOOL_COMMAND