note description: "Window to create dynamic libraries" legal: "See notice at end of class." status: "See notice at end of class." date: "$Date$" revision: "$Revision$" class EB_DYNAMIC_LIB_WINDOW inherit EB_WINDOW redefine refresh, build_file_menu, build_edit_menu, build_menu_bar, init_commands, init_size_and_position, destroy end SHARED_EIFFEL_PROJECT EB_SHARED_PREFERENCES export {NONE} all end EB_PIXMAPABLE_ITEM_PIXMAP_FACTORY export {NONE} all end PLATFORM export {NONE} all end EB_FILE_DIALOG_CONSTANTS export {NONE} all end EIFFEL_LAYOUT export {NONE} all end INTERNAL_COMPILER_STRING_EXPORTER -- For fast UTF-8 name comparison export {NONE} all end create {EB_WINDOW_MANAGER} make feature {NONE} -- Initialization make -- Create a new tool with `man' as manager. do -- Vision2 initialization create window window.show_actions.extend (agent window_displayed) init_size_and_position window.close_request_actions.wipe_out window.close_request_actions.put_front (agent destroy) window.set_icon_pixmap (pixmap) -- Initialize commands and connect them. init_commands -- Build widget system & menus. build_interface build_menus -- Set up the minimize title if it's not done if minimized_title = Void or else minimized_title.is_empty then set_minimized_title (title) end register_action (window.focus_in_actions, agent window_manager.set_focused_window (Current)) initialized := True create exports.make (10) end build_menus -- Build all menus. do -- Build each menu build_file_menu build_edit_menu -- Build the menu bar. build_menu_bar end build_interface local vb: EV_VERTICAL_BOX w: INTEGER iw: INTEGER ccw: INTEGER f: EV_FONT sep: EV_HORIZONTAL_SEPARATOR do set_title (Interface_names.t_Dynamic_lib_window) build_tool_bar enable_accelerators create vb create sep vb.extend (sep) vb.disable_item_expand (sep) vb.extend (tool_bar) vb.disable_item_expand (tool_bar) create exports_list if is_windows then exports_list.set_column_titles (<>) else exports_list.set_column_titles (<>) end exports_list.select_actions.extend (agent item_selected) exports_list.deselect_actions.extend (agent item_deselected) exports_list.drop_actions.extend (agent drop_feature) exports_list.disable_multiple_selection vb.extend (exports_list) window.extend (vb) -- We give correct sizes to the columns. -- A definite size for index and calling convention, the rest for the other columns. f := create {EV_FONT} --| Because of naughty Vision2, the multi_column_list doesn't know its size until it is displayed. --w := exports_list.width w := initial_width - 10 if is_windows then -- Width of the `Index' column. iw := f.string_width ("Index") + 30 -- Width of the `Calling convention' column. from valid_calling_conventions.start until valid_calling_conventions.after loop ccw := ccw.max (f.string_width (valid_calling_conventions.item)) valid_calling_conventions.forth end ccw := ccw + 40 w := w - iw - ccw end -- There remains 4 columns. w := w // 4 if is_windows then exports_list.set_column_widths (<>) else exports_list.set_column_widths (<>) end end init_size_and_position -- Retrieve the size of `Current' from the preferences and affect it. do window.set_size (initial_width, initial_height) end init_commands -- Create all the commands `Current' uses. local kcsts: EV_KEY_CONSTANTS do create kcsts -- Create `new_cmd'. create new_cmd.make new_cmd.set_pixel_buffer (pixmaps.icon_pixmaps.new_document_icon_buffer) new_cmd.set_tooltip (Interface_names.e_New_dynamic_lib_definition) new_cmd.set_menu_name (Interface_names.m_New) new_cmd.set_name ("new_dynamic_lib_definition") new_cmd.set_accelerator (create {EV_ACCELERATOR}.make_with_key_combination ( create {EV_KEY}.make_with_code (kcsts.Key_n), True, False, False)) new_cmd.add_agent (agent new_def_file) new_cmd.enable_sensitive -- Create `open_cmd'. create open_cmd.make open_cmd.set_pixel_buffer (pixmaps.icon_pixmaps.general_open_icon_buffer) open_cmd.set_tooltip (Interface_names.e_Open_dynamic_lib_definition) open_cmd.set_menu_name (Interface_names.m_Open_new) open_cmd.set_name ("open_dynamic_lib_definition") open_cmd.add_agent (agent open_def_file) open_cmd.set_accelerator (create {EV_ACCELERATOR}.make_with_key_combination ( create {EV_KEY}.make_with_code (kcsts.Key_o), True, False, False)) open_cmd.enable_sensitive -- Create `save_cmd'. create save_cmd.make save_cmd.set_pixel_buffer (pixmaps.icon_pixmaps.general_save_icon_buffer) save_cmd.set_tooltip (Interface_names.e_Save_dynamic_lib_definition) save_cmd.set_menu_name (Interface_names.m_Save_new) save_cmd.set_name ("save_dynamic_lib_definition") save_cmd.add_agent (agent save_def_file) save_cmd.set_accelerator (create {EV_ACCELERATOR}.make_with_key_combination ( create {EV_KEY}.make_with_code (kcsts.Key_s), True, False, False)) save_cmd.enable_sensitive -- Create `save_as_cmd'. create save_as_cmd.make save_as_cmd.set_menu_name (Interface_names.m_Save_as) save_as_cmd.set_name ("save_dynamic_lib_definition_as") save_as_cmd.add_agent (agent save_def_file_as) save_as_cmd.enable_sensitive -- Create `add_feature_cmd'. create add_feature_cmd.make add_feature_cmd.set_pixel_buffer (pixmaps.icon_pixmaps.general_add_icon_buffer) add_feature_cmd.set_tooltip (Interface_names.e_Add_exported_feature) add_feature_cmd.set_menu_name (Interface_names. m_Add_exported_feature) add_feature_cmd.set_name ("add_exported_feature") add_feature_cmd.add_agent (agent add_feature) add_feature_cmd.set_accelerator (create {EV_ACCELERATOR}.make_with_key_combination ( create {EV_KEY}.make_with_code (kcsts.Key_a), True, False, False)) add_feature_cmd.enable_sensitive -- Create `edit_feature_cmd'. create edit_feature_cmd.make edit_feature_cmd.set_pixel_buffer (pixmaps.icon_pixmaps.general_edit_icon_buffer) edit_feature_cmd.set_tooltip (Interface_names.e_Edit_exported_feature) edit_feature_cmd.set_menu_name (Interface_names.m_Edit_exported_feature) edit_feature_cmd.set_name ("edit_exported_feature") edit_feature_cmd.add_agent (agent edit_selected_feature) edit_feature_cmd.set_accelerator (create {EV_ACCELERATOR}.make_with_key_combination ( create {EV_KEY}.make_with_code (kcsts.Key_e), True, False, False)) edit_feature_cmd.disable_sensitive -- Create `remove_feature_cmd'. create remove_feature_cmd.make remove_feature_cmd.set_pixel_buffer (pixmaps.icon_pixmaps.general_delete_icon_buffer) remove_feature_cmd.set_tooltip (Interface_names.e_Remove_exported_feature) remove_feature_cmd.set_menu_name (Interface_names.m_Remove_exported_feature) remove_feature_cmd.set_name ("remove_exported_feature") remove_feature_cmd.add_agent (agent remove_selected_feature) remove_feature_cmd.set_accelerator (create {EV_ACCELERATOR}.make_with_key_combination ( create {EV_KEY}.make_with_code (kcsts.Key_delete), False, False, False)) remove_feature_cmd.disable_sensitive -- Create `check_exports_cmd'. create check_exports_cmd.make check_exports_cmd.set_pixel_buffer (pixmaps.icon_pixmaps.general_check_document_icon_buffer) check_exports_cmd.set_tooltip (Interface_names.e_Check_exports) check_exports_cmd.set_menu_name (Interface_names.m_Check_exports) check_exports_cmd.set_name ("check_exports") check_exports_cmd.add_agent (agent check_exported_features) check_exports_cmd.set_accelerator (create {EV_ACCELERATOR}.make_with_key_combination ( create {EV_KEY}.make_with_code (kcsts.Key_c), True, False, False)) check_exports_cmd.enable_sensitive end build_file_menu -- Create and build `file_menu'. local menu_item: EV_MENU_ITEM command_menu_item: EB_COMMAND_MENU_ITEM do create file_menu.make_with_text (Interface_names.m_File) command_menu_item := new_cmd.new_menu_item file_menu.extend (command_menu_item) auto_recycle (command_menu_item) command_menu_item := open_cmd.new_menu_item file_menu.extend (command_menu_item) auto_recycle (command_menu_item) command_menu_item := save_cmd.new_menu_item file_menu.extend (command_menu_item) auto_recycle (command_menu_item) command_menu_item := save_as_cmd.new_menu_item file_menu.extend (command_menu_item) auto_recycle (command_menu_item) file_menu.extend (create {EV_MENU_SEPARATOR}) create menu_item.make_with_text (Interface_names.m_Close) menu_item.select_actions.extend (agent destroy) file_menu.extend (menu_item) end build_edit_menu -- Generate `edit_menu'. local command_menu_item: EB_COMMAND_MENU_ITEM do create edit_menu.make_with_text (Interface_names.m_Edit) command_menu_item := add_feature_cmd.new_menu_item edit_menu.extend (command_menu_item) auto_recycle (command_menu_item) command_menu_item := edit_feature_cmd.new_menu_item edit_menu.extend (command_menu_item) auto_recycle (command_menu_item) command_menu_item := remove_feature_cmd.new_menu_item edit_menu.extend (command_menu_item) auto_recycle (command_menu_item) command_menu_item := check_exports_cmd.new_menu_item edit_menu.extend (command_menu_item) auto_recycle (command_menu_item) end build_menu_bar -- Generate `menu_bar' and fill it with the correct menus. local mb: EV_MENU_BAR do create mb mb.extend (file_menu) mb.extend (edit_menu) window.set_menu_bar (mb) end build_tool_bar -- Create `toolbar' and display it. local tb: SD_TOOL_BAR tbit: EB_SD_COMMAND_TOOL_BAR_BUTTON sep: EV_VERTICAL_SEPARATOR do create tool_bar create tb.make tbit := new_cmd.new_sd_toolbar_item (False) tb.extend (tbit) auto_recycle (tbit) tbit := open_cmd.new_sd_toolbar_item (False) tb.extend (tbit) auto_recycle (tbit) tbit := save_cmd.new_sd_toolbar_item (False) tb.extend (tbit) auto_recycle (tbit) tool_bar.extend (tb) tool_bar.disable_item_expand (tb) tb.compute_minimum_size create sep tool_bar.extend (sep) tool_bar.disable_item_expand (sep) create tb.make tbit := check_exports_cmd.new_sd_toolbar_item (False) tb.extend (tbit) auto_recycle (tbit) tbit := add_feature_cmd.new_sd_toolbar_item (False) tb.extend (tbit) auto_recycle (tbit) tbit := edit_feature_cmd.new_sd_toolbar_item (False) tb.extend (tbit) auto_recycle (tbit) tbit := remove_feature_cmd.new_sd_toolbar_item (False) tb.extend (tbit) auto_recycle (tbit) tool_bar.extend (tb) tool_bar.disable_item_expand (tb) tb.compute_minimum_size end enable_accelerators -- Enable the accelerators of all commands. local acc: EV_ACCELERATOR do acc := new_cmd.accelerator if acc /= Void then window.accelerators.extend (acc) end acc := open_cmd.accelerator if acc /= Void then window.accelerators.extend (acc) end acc := save_cmd.accelerator if acc /= Void then window.accelerators.extend (acc) end acc := save_as_cmd.accelerator if acc /= Void then window.accelerators.extend (acc) end acc := remove_feature_cmd.accelerator if acc /= Void then window.accelerators.extend (acc) end acc := add_feature_cmd.accelerator if acc /= Void then window.accelerators.extend (acc) end acc := edit_feature_cmd.accelerator if acc /= Void then window.accelerators.extend (acc) end acc := check_exports_cmd.accelerator if acc /= Void then window.accelerators.extend (acc) end end feature -- Access pixmap: EV_PIXMAP -- Pixmap representing Current window. do Result := pixmaps.icon_pixmaps.general_dialog_icon end changed: BOOLEAN -- Are there unsaved modifications? feature -- Status setting give_focus -- Grab the focus. do exports_list.set_focus end destroy -- Destroy `Current'. do if changed and not confirmed then (create {ES_SHARED_PROMPT_PROVIDER}).prompts.show_warning_prompt_with_cancel ( Warning_messages.w_Unsaved_changes, window, agent force_destroy, Void) else Precursor {EB_WINDOW} end end feature -- Basic operations save -- Save `Current's state into a .def file. -- May be cancelled by the user. do save_def_file end feature -- Stone process refresh -- Synchronize the display with the internal dynamic library representation. do refresh_list end synchronize -- A compilation is over, update `Current's internal state. local exp: DYNAMIC_LIB_EXPORT_FEATURE do from exports.start until exports.after loop exp := exports.item exp.synchronize if valid_exported_feature (exp) then exports.forth else exports.remove changed := True end end refresh_list end feature -- Basic operation feature -- Window Settings feature -- Formats feature {NONE} -- Status exports: ARRAYED_LIST [DYNAMIC_LIB_EXPORT_FEATURE] -- The abstract representation for all the exported features. file_name: PATH -- The name of the file we are currently working on. -- May be Void if no file is loaded. feature {NONE} -- Implementation: File operations open_def_file -- Let the user select a `.def' file and open it. -- Cancelling is possible. do if changed then (create {ES_SHARED_PROMPT_PROVIDER}).prompts.show_warning_prompt_with_cancel ( Warning_messages.w_Unsaved_changes, window, agent ask_for_file_name (True, agent load_dynamic_lib), Void) else ask_for_file_name (True, agent load_dynamic_lib) end end save_def_file -- Write the contents of `Current' to `file_name' if any, -- Prompt the user for a file name otherwise. -- Cancelling is possible. local pb: INTEGER do pb := export_definition_problem if pb = 0 then actually_save else (create {ES_SHARED_PROMPT_PROVIDER}).prompts.show_warning_prompt_with_cancel ( Warning_messages.w_Save_invalid_definition, window, agent actually_save, Void) end end save_def_file_as -- Prompt the user for a file name and save the contents of `Current' to it. -- Cancelling is possible. local pb: INTEGER do pb := export_definition_problem if pb = 0 then ask_for_file_name (False, agent actually_save) else (create {ES_SHARED_PROMPT_PROVIDER}).prompts.show_warning_prompt_with_cancel ( Warning_messages.w_Save_invalid_definition, window, agent ask_for_file_name (False, agent actually_save), Void) end end new_def_file -- Prompt the user for a file name and create a new `.def' file. -- Cancelling is possible. do if changed then (create {ES_SHARED_PROMPT_PROVIDER}).prompts.show_question_prompt ( Warning_messages.w_Unsaved_changes, window, agent reset, Void) else reset end end actually_save -- Save the definition whether or not there are errors. do save_ok := False save_to_dynamic_lib save_dynamic_lib if save_ok then changed := False end end force_destroy -- Destroy without asking. do confirmed := True destroy end confirmed: BOOLEAN -- Did the user already confirm he wanted to exit? feature {NONE} -- Implementation: Feature operations add_feature -- Prompt the user for a feature to add to the list. -- May be cancelled. do create_properties_dialog (False) properties_dialog.show_modal_to_window (window) end drop_feature (fst: FEATURE_STONE) -- Add the dropped feature associated to `fst' to the list. -- Prompt the user for the creation routine, if necessary. -- May be cancelled. do current_class := fst.e_feature.associated_class current_feature := fst.e_feature if not valid_class (current_class) then prompts.show_error_prompt (Warning_messages.w_Class_cannot_export, window, Void) elseif not valid_feature (current_feature, current_class) then prompts.show_error_prompt (Warning_messages.w_Feature_cannot_be_exported, window, Void) else current_creation_routine := Void current_alias := Void current_index := 0 current_calling_convention := Void choose_creation_routine (agent generate_new_exported_feature) end end edit_selected_feature -- Modify the exportation properties of the selected feature. do if attached exports_list.selected_item as sel then if attached {DYNAMIC_LIB_EXPORT_FEATURE} sel.data as f then modified_exported_feature := f create_properties_dialog (True) initialize_modification_dialog properties_dialog.show_modal_to_window (window) else modified_exported_feature := Void end end end remove_selected_feature -- Remove the selected feature from the exported features. do if attached exports_list.selected_item as sel and then attached {DYNAMIC_LIB_EXPORT_FEATURE} sel.data as f then changed := True exports.start exports.prune_all (f) refresh_list end end check_exported_features -- Check the validity of the exported features, -- both one at a time and globally. local pb: INTEGER err: EV_MULTI_COLUMN_LIST_ROW do pb := export_definition_problem if pb = 0 then (create {ES_SHARED_PROMPT_PROVIDER}).prompts.show_warning_prompt (Warning_messages.w_No_errors_found, window, Void) elseif pb = -1 then (create {ES_SHARED_PROMPT_PROVIDER}).prompts.show_error_prompt (Warning_messages.w_Conflicting_exports, window, Void) else err := exports_list.i_th (pb) if err /= Void then err.enable_select end (create {ES_SHARED_PROMPT_PROVIDER}).prompts.show_error_prompt (Warning_messages.w_Invalid_feature_exportation, window, Void) end end reset -- Wipe out all data (`file_name', `exports' and `exports_list'). do exports.wipe_out exports_list.wipe_out file_name := Void end feature {NONE} -- Implementation: Basic event handling item_selected (it: EV_MULTI_COLUMN_LIST_ROW) -- An item was selected in `exports_list'. Enable the related commands. do edit_feature_cmd.enable_sensitive remove_feature_cmd.enable_sensitive end item_deselected (it: EV_MULTI_COLUMN_LIST_ROW) -- An item was selected in `exports_list'. Enable the related commands. do edit_feature_cmd.disable_sensitive remove_feature_cmd.disable_sensitive end feature {NONE} -- Implementation: Graphical interface exports_list: EV_MULTI_COLUMN_LIST -- The list displaying all currently exported features. tool_bar: EV_HORIZONTAL_BOX -- The container of `Current's toolbar. new_cmd: EB_STANDARD_CMD -- Command to create a new '.def' file. open_cmd: EB_STANDARD_CMD -- Command to open a '.def' file. save_cmd: EB_STANDARD_CMD -- Command to save the current '.def' file. save_as_cmd: EB_STANDARD_CMD -- Command to save a '.def' file. remove_feature_cmd: EB_STANDARD_CMD -- Command to remove an exported feature. add_feature_cmd: EB_STANDARD_CMD -- Command to add an exported feature. edit_feature_cmd: EB_STANDARD_CMD -- Command to modify the export status of an exported feature. check_exports_cmd: EB_STANDARD_CMD -- Command to check the validity of the library definition as a whole. initial_width: INTEGER -- Initial width for the dialog. do Result := preferences.misc_data.dyn_lib_window_width end initial_height: INTEGER -- Initial width for the dialog. do Result := preferences.misc_data.dyn_lib_window_height end save_width_and_height -- Save current width and height to the preferences. do preferences.misc_data.dyn_lib_window_width_preference.set_value (window.width) preferences.misc_data.dyn_lib_window_height_preference.set_value (window.height) ensure size_saved: initial_width = window.width and initial_height = window.height end refresh_list -- Refresh `exports_list' according to `exports'. local sel: EV_MULTI_COLUMN_LIST_ROW do sel := exports_list.selected_item exports_list.wipe_out from exports.start until exports.after loop exports_list.extend (feature_to_row (exports.item)) exports.forth end if sel /= Void then item_deselected (sel) end end feature_to_row (exp: DYNAMIC_LIB_EXPORT_FEATURE): EV_MULTI_COLUMN_LIST_ROW -- Convert `exp' into a row for `exports_list'. require feature_not_void: exp /= Void do create Result Result.set_data (exp) if exp.compiled_class /= Void then Result.extend (exp.compiled_class.name_in_upper) else Result.extend (empty_string) end Result.extend (if attached exp.creation_routine as r then r.name_32 else empty_string end) Result.extend (if attached exp.routine as r then r.name_32 else empty_string end) Result.extend (if attached exp.alias_name_32 as l_name then l_name else empty_string end) if is_windows then if exp.index = 0 then Result.extend (empty_string) else Result.extend (exp.index.out) end if exp.call_type /= Void then Result.extend (exp.call_type) else Result.extend (empty_string) end end end empty_string: STRING_32 = "" feature {NONE} -- Implementation: Creation routine selection choose_creation_routine (next_action: PROCEDURE) -- If possible, find a valid creation routine of `current_class', -- and set `current_creation_routine' after asking the user if necessary. -- Call `next_action' iff a creation routine was chosen. require current_class_set: valid_class (current_class) do call_back := next_action creation_routine_list := valid_creation_routines (current_class) if creation_routine_list /= Void then if creation_routine_list.count = 1 then current_creation_routine := creation_routine_list.first next_action.call (Void) elseif creation_routine_list.count > 1 then display_creation_routine_choice else --| Nothing to choose. prompts.show_error_prompt (Warning_messages.w_No_valid_creation_routine, window, Void) end else --| Nothing to choose. prompts.show_error_prompt (Warning_messages.w_No_valid_creation_routine, window, Void) end end valid_creation_routines (cl:CLASS_C): LIST [E_FEATURE] -- Calculate the list of valid creation procedures. require valid_class_c: cl /= Void and then cl.has_feature_table do create {ARRAYED_LIST [E_FEATURE]} Result.make (5) if attached cl.creators as cs then across cs as c loop if attached cl.feature_with_name_id (c.key) as f and then not f.has_arguments then Result.extend (f) end end elseif attached cl.default_create_feature as default_create_feature then Result.extend (default_create_feature.api_feature (cl.class_id)) end ensure not_void_result: Result /= Void only_valid_creation_routines: Result.for_all (agent valid_creation_routine (?, cl)) end display_creation_routine_choice -- Display feature names from `creation_routine_list' to `choice'. require feature_list_not_void: creation_routine_list /= Void feature_list_has_several_elements: creation_routine_list.count > 1 local choice: EB_CHOICE_DIALOG feature_names: ARRAYED_LIST [STRING_32] feature_pixmaps: ARRAYED_LIST [EV_PIXMAP] do create feature_names.make (creation_routine_list.count) create feature_pixmaps.make (creation_routine_list.count) from creation_routine_list.start until creation_routine_list.after loop feature_names.extend (creation_routine_list.item.name_32) feature_pixmaps.extend (pixmap_from_e_feature (creation_routine_list.item)) creation_routine_list.forth end if not feature_names.is_empty then if feature_names.count = 1 then process_creation_routine_callback (1) else create choice.make_default (window, agent process_creation_routine_callback (?)) choice.set_title (Interface_names.t_Select_feature) choice.set_list (feature_names, feature_pixmaps) choice.set_position (window.screen_x + window.width // 3, window.screen_y + window.height // 3) choice.show end else -- No creation routine is available end end process_creation_routine_callback (pos: INTEGER) -- The choice `pos' has been selected, process the choice. require looking_for_a_creation_routine: creation_routine_list /= Void do if pos > 0 then current_creation_routine := creation_routine_list.i_th (pos) end creation_routine_list := Void call_back.call (Void) end creation_routine_list: LIST [E_FEATURE] -- The creation routines of `current_class' among which the user may choose. call_back: PROCEDURE -- What should be executed after choosing a creation routine. feature {NONE} -- Implementation: Low_level dialog, file operations save_to_dynamic_lib -- Save the current `exports' to `dynamic_library'. local exp: DYNAMIC_LIB_EXPORT_FEATURE do create dynamic_library -- This is necessary because the E_DYNAMIC_LIB's content is once (!). dynamic_library.dynamic_lib_exports.wipe_out from exports.start until exports.after loop exp := exports.item if valid_exported_feature (exp) then dynamic_library.add_export_feature (exp.compiled_class, exp.creation_routine, exp.routine, exp.index, exp.alias_name, exp.call_type) end exports.forth end end save_dynamic_lib -- Write the contents of `dynamic_lib' to `file_name'. require valid_dynamic_library: dynamic_library /= Void local retried: BOOLEAN f: PLAIN_TEXT_FILE do save_ok := False if not retried then if file_name /= Void then -- It is really a save operation. create f.make_with_path (file_name) f.create_read_write dynamic_library.save_to_file (f) f.close save_ok := True else -- It is really a save as operation. ask_for_file_name (False, agent save_dynamic_lib) end else if attached file_name as l_fn then prompts.show_error_prompt (Warning_messages.w_Cannot_save_library (l_fn.name), window, Void) end end rescue retried := True retry end save_ok: BOOLEAN -- Was the last save effective? load_ok: BOOLEAN -- Was the last load effective? load_dynamic_lib -- Initialize `dynamic_lib' from `file_name'. local retried: BOOLEAN f: PLAIN_TEXT_FILE do if not retried then if file_name /= Void then create dynamic_library create f.make_with_path (file_name) f.open_read dynamic_library.parse_exports_from_file (f) if not dynamic_library.is_content_valid then prompts.show_error_prompt (Warning_messages.w_Error_parsing_the_library_file, window, Void) end f.close load_ok := False load_from_dynamic_lib if load_ok then changed := False end else ask_for_file_name (True, agent load_dynamic_lib) end else if attached file_name as l_fn then prompts.show_error_prompt (Warning_messages.w_Cannot_load_library (l_fn.name), window, Void) end end rescue retried := True retry end load_from_dynamic_lib -- Retrieve the information in `dynamic_library' definition to initialize `Current'. require dynamic_library_initialized: dynamic_library /= Void local dynamic_lib_exports: HASH_TABLE [LINKED_LIST[DYNAMIC_LIB_EXPORT_FEATURE],INTEGER] exp_list: LINKED_LIST[DYNAMIC_LIB_EXPORT_FEATURE] do dynamic_lib_exports := dynamic_library.dynamic_lib_exports exports.wipe_out exports_list.wipe_out from dynamic_lib_exports.start until dynamic_lib_exports.after loop exp_list := dynamic_lib_exports.item_for_iteration from exp_list.start until exp_list.after loop exports.extend (exp_list.item) exports_list.extend (feature_to_row (exp_list.item)) exp_list.forth end dynamic_lib_exports.forth end load_ok := True end ask_for_file_name (load: BOOLEAN; next_action: PROCEDURE) -- Prompt the user for a `.def' file, set `file_name' to the chosen file name, and execute `next_action'. -- If `load' then we assume we want to open a file. Otherwise we want to save it. local dd: EB_FILE_DIALOG l_pref: PATH_PREFERENCE do file_call_back := next_action if load then l_pref := preferences.dialog_data.last_opened_dynamic_lib_directory_preference if l_pref.value = Void or else l_pref.value.is_empty then l_pref.set_value (eiffel_layout.user_projects_path) end create {EB_FILE_OPEN_DIALOG} dd.make_with_preference (l_pref) else l_pref := preferences.dialog_data.last_saved_dynamic_lib_directory_preference if l_pref.value = Void or else l_pref.value.is_empty then l_pref.set_value (eiffel_layout.user_projects_path) end create {EB_FILE_SAVE_DIALOG} dd.make_with_preference (l_pref) end dd.set_start_path (Eiffel_project.project_directory.path) set_dialog_filters_and_add_all (dd, {ARRAY [STRING_32]} <>) dd.ok_actions.extend (agent file_was_chosen (dd)) dd.show_modal_to_window (window) end file_was_chosen (dd: EB_FILE_DIALOG) -- The user selected a file in `dd'. -- Set `file_name' accordingly and call `file_call_back'. require valid_dialog: dd /= Void local fn: like file_name do fn := dd.full_file_path if not fn.is_empty then if not fn.has_extension ("def") then -- No extension or not a "def" extension fn := fn.appended_with_extension ("def") end file_name := fn file_call_back.call (Void) end end dynamic_library: E_DYNAMIC_LIB -- Helper to read/write .def files. file_call_back: PROCEDURE -- Action performed after a file has been chosen. feature {NONE} -- Implementation: Feature creation generate_new_exported_feature -- Effectively add an element to `exports' and `exports_list'. require valid_export: valid_export_parameters (current_class, current_creation_routine, current_feature, current_alias, current_index, current_calling_convention) local exp: DYNAMIC_LIB_EXPORT_FEATURE do if current_feature = current_creation_routine then current_feature := Void end create exp.make (current_class, current_creation_routine, current_feature) if current_alias /= Void then exp.set_alias_name (current_alias) end if current_index /= 0 then exp.set_index (current_index) end if current_calling_convention /= Void then exp.set_call_type (current_calling_convention) end exports.extend (exp) exports_list.extend (feature_to_row (exp)) changed := True ensure new_export_displayed: exports_list.count = (old exports_list.count) + 1 new_export_stored: exports.count = (old exports.count) + 1 end current_class: CLASS_C -- The class from which a new feature should be exported. current_creation_routine: E_FEATURE -- The creation routine used to create `current_class' when exporting `current_feature'. current_feature: E_FEATURE -- The new feature that should be exported. current_alias: STRING -- Name under which `current_feature' should be exported. current_index: INTEGER -- Index in the dynamic library which should correspond to `current_feature'. current_calling_convention: STRING -- Calling convention that should be used to call `current_feature' in the dynamic library. feature {NONE} -- Implementation: Properties dialog create_properties_dialog (for_modification: BOOLEAN) -- Generate `properties_dialog' and if `for_modification', give it a layout of modification dialog. require possible_to_modify: for_modification implies modified_exported_feature /= Void and then modified_exported_feature.routine /= Void and then modified_exported_feature.compiled_class /= Void local ilab: EV_LABEL mainvb: EV_VERTICAL_BOX vb: EV_VERTICAL_BOX fr: EV_FRAME hb: EV_HORIZONTAL_BOX f: EV_FONT info_width: INTEGER ccw: INTEGER cancelb: EV_BUTTON do create properties_dialog properties_dialog.set_title (Interface_names.t_Feature_properties) properties_dialog.set_icon_pixmap (pixmaps.icon_pixmaps.general_dialog_icon) create mainvb properties_dialog.extend (mainvb) mainvb.set_padding (Layout_constants.small_padding_size) mainvb.set_border_width (Layout_constants.default_border_size) create vb vb.set_border_width (Layout_constants.small_border_size) vb.set_padding (Layout_constants.small_padding_size) -- Determine the width of the info labels. f := create {EV_FONT} info_width := f.string_width (Interface_names.l_class_colon) info_width := info_width.max (f.string_width (Interface_names.l_Feature_colon)) info_width := info_width.max (f.string_width (Interface_names.l_Alias_name)) info_width := info_width.max (f.string_width (Interface_names.l_Creation)) info_width := info_width.max (f.string_width (Interface_names.l_Index)) info_width := info_width.max (f.string_width (Interface_names.l_Calling_convention)) create hb hb.set_padding (Layout_constants.default_padding_size) create ilab.make_with_text (Interface_names.l_class_colon) ilab.align_text_left ilab.set_minimum_width (info_width) hb.extend (ilab) hb.disable_item_expand (ilab) create class_field if for_modification then class_field.disable_edit else class_field.return_actions.extend (agent new_class_name (True)) class_field.focus_out_actions.extend (agent new_class_name (False)) class_field.change_actions.extend (agent may_enable_ok_button) end class_field.set_minimum_width (f.string_width ("A_LONG_CLASS_NAME")) hb.extend (class_field) vb.extend (hb) vb.disable_item_expand (hb) create hb hb.set_padding (Layout_constants.default_padding_size) create ilab.make_with_text (Interface_names.l_Creation) ilab.align_text_left ilab.set_minimum_width (info_width) hb.extend (ilab) hb.disable_item_expand (ilab) create creation_combo creation_combo.disable_edit hb.extend (creation_combo) vb.extend (hb) vb.disable_item_expand (hb) create hb hb.set_padding (Layout_constants.default_padding_size) create ilab.make_with_text (Interface_names.l_Feature_colon) ilab.align_text_left ilab.set_minimum_width (info_width) hb.extend (ilab) hb.disable_item_expand (ilab) create feature_field if for_modification then feature_field.disable_edit else feature_field.change_actions.extend (agent may_enable_ok_button) end hb.extend (feature_field) vb.extend (hb) vb.disable_item_expand (hb) create hb hb.set_padding (Layout_constants.default_padding_size) create ilab.make_with_text (Interface_names.l_Alias_name) ilab.align_text_left ilab.set_minimum_width (info_width) hb.extend (ilab) hb.disable_item_expand (ilab) create alias_field hb.extend (alias_field) vb.extend (hb) vb.disable_item_expand (hb) if is_windows then create hb hb.set_padding (Layout_constants.default_padding_size) create ilab.make_with_text (Interface_names.l_Index) ilab.align_text_left ilab.set_minimum_width (info_width) hb.extend (ilab) hb.disable_item_expand (ilab) create index_field index_field.set_leap (1) index_field.value_range.adapt (0 |..| ({INTEGER_32} 1 |<< 15 - 1)) index_field.set_minimum_width (f.string_width ("20") + 50) hb.extend (index_field) hb.disable_item_expand (index_field) vb.extend (hb) vb.disable_item_expand (hb) create hb hb.set_padding (Layout_constants.default_padding_size) create ilab.make_with_text (Interface_names.l_Calling_convention) ilab.align_text_left ilab.set_minimum_width (info_width) hb.extend (ilab) hb.disable_item_expand (ilab) create call_combo call_combo.disable_edit hb.extend (call_combo) from valid_calling_conventions.start until valid_calling_conventions.after loop ccw := ccw.max (f.string_width (valid_calling_conventions.item)) valid_calling_conventions.forth end ccw := ccw + 30 call_combo.set_minimum_width (ccw) from valid_calling_conventions.start until valid_calling_conventions.after loop call_combo.extend (create {EV_LIST_ITEM}.make_with_text (valid_calling_conventions.item)) valid_calling_conventions.forth end hb.disable_item_expand (call_combo) vb.extend (hb) vb.disable_item_expand (hb) end create fr.make_with_text (Interface_names.l_Feature_properties) fr.extend (vb) mainvb.extend (fr) create okb.make_with_text (Interface_names.b_Ok) Layout_constants.set_default_width_for_button (okb) if for_modification then okb.select_actions.extend (agent on_modification_ok) properties_dialog.show_actions.extend (agent alias_field.set_focus) else okb.select_actions.extend (agent on_creation_ok) properties_dialog.show_actions.extend (agent class_field.set_focus) end create cancelb.make_with_text (Interface_names.b_Cancel) Layout_constants.set_default_width_for_button (cancelb) cancelb.select_actions.extend (agent properties_dialog.destroy) create hb hb.set_padding (Layout_constants.default_padding_size) hb.extend (create {EV_CELL}) hb.extend (okb) hb.disable_item_expand (okb) hb.extend (cancelb) hb.disable_item_expand (cancelb) mainvb.extend (hb) properties_dialog.set_maximum_height (properties_dialog.height) properties_dialog.set_default_cancel_button (cancelb) properties_dialog.set_default_push_button (okb) if not for_modification then okb.disable_sensitive end ensure dialog_created: valid_properties_dialog end valid_properties_dialog: BOOLEAN -- Contract support. do Result := properties_dialog /= Void and class_field /= Void and feature_field /= Void and creation_combo /= Void and alias_field /= Void if Result and is_windows then Result := index_field /= Void and call_combo /= Void end end initialize_modification_dialog -- Fill in the fields of `properties_dialog' according to `modified_exported_feature'. require properties_dialog_created: valid_properties_dialog feature_being_modified: modified_exported_feature /= Void valid_modified_feature: modified_exported_feature.compiled_class /= Void and modified_exported_feature.routine /= Void local cit: EV_LIST_ITEM curcr: STRING_32 crname: STRING_32 do available_creation_routines := valid_creation_routines (modified_exported_feature.compiled_class) class_field.set_text (modified_exported_feature.compiled_class.name) feature_field.set_text (modified_exported_feature.routine.name_32) if modified_exported_feature.creation_routine /= Void then curcr := modified_exported_feature.creation_routine.name_32 end from available_creation_routines.start until available_creation_routines.after loop crname := available_creation_routines.item.name_32 create cit.make_with_text (crname) creation_combo.extend (cit) if curcr /= Void and then curcr.same_string_general (crname) then cit.enable_select end available_creation_routines.forth end if attached modified_exported_feature.alias_name_32 as l_name then alias_field.set_text (l_name) end if is_windows then if modified_exported_feature.index > 0 then index_field.set_value (modified_exported_feature.index) end if attached modified_exported_feature.call_type as curcc then from call_combo.start until call_combo.after loop cit := call_combo.item if cit /= Void and then cit.text.same_string_general (curcc) then cit.enable_select end call_combo.forth end end end end on_modification_ok -- Check if the modified feature is valid enough, -- update `modified_exported_feature' if necessary. require really_modifying: valid_properties_dialog feature_being_modified: modified_exported_feature /= Void and then modified_exported_feature.compiled_class /= Void and then modified_exported_feature.routine /= Void local cl: CLASS_C f: E_FEATURE cr: E_FEATURE al: STRING ind: INTEGER cc: STRING do cl := modified_exported_feature.compiled_class f := modified_exported_feature.routine cr := cl.feature_with_name ({UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (creation_combo.selected_item.text)) al := {UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (alias_field.text) if is_windows then ind := index_field.value cc := {UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (call_combo.selected_item.text) end if not valid_export_parameters (cl, cr, f, al, ind, cc) then if cl = Void then prompts.show_error_prompt (Warning_messages.w_Not_a_compiled_class (class_field.text), properties_dialog, Void) elseif not valid_class (cl) then prompts.show_error_prompt (Warning_messages.w_Class_cannot_export, properties_dialog, Void) elseif f = Void then prompts.show_error_prompt (Warning_messages.w_No_exported_feature (feature_field.text, class_field.text), properties_dialog, Void) elseif not valid_feature (f, cl) then prompts.show_error_prompt (Warning_messages.w_Feature_cannot_be_exported, properties_dialog, Void) elseif not valid_creation_routine (cr, cl) then prompts.show_error_prompt (Warning_messages.w_No_valid_creation_routine, properties_dialog, Void) elseif not al.is_empty and then not valid_alias (al) then prompts.show_error_prompt (Warning_messages.w_Invalid_alias, properties_dialog, Void) elseif is_windows and then ind /= 0 and then not valid_index (ind) then prompts.show_error_prompt (Warning_messages.w_Invalid_index, properties_dialog, Void) else prompts.show_error_prompt (Warning_messages.w_Invalid_parameters, properties_dialog, Void) end else -- Ah we can update the exported feature. modified_exported_feature.set_creation_routine (cr) if not al.is_empty then modified_exported_feature.set_alias_name (al) else modified_exported_feature.remove_alias_name end if is_windows then if ind = 0 then modified_exported_feature.remove_index else modified_exported_feature.set_index (ind) end if not default_calling_convention.same_string_general (cc) then modified_exported_feature.set_call_type (cc) else modified_exported_feature.remove_call_type end else modified_exported_feature.remove_index modified_exported_feature.remove_call_type end properties_dialog.destroy changed := True refresh_list end end may_enable_ok_button -- Depending on the content of `properties', enable or disable -- default push button. Enabled when both class and feature text -- field are filled, disabled otherwise. require properties_dialog_not_void: properties_dialog /= Void do if not class_field.text.is_empty and then not feature_field.text.is_empty then properties_dialog.default_push_button.enable_sensitive else properties_dialog.default_push_button.disable_sensitive end end on_creation_ok -- Check if the modified feature is valid enough, -- update `modified_exported_feature' if necessary. require really_creating: valid_properties_dialog local cl: CLASS_C f: E_FEATURE cr: E_FEATURE al: STRING ind: INTEGER cc: STRING tmp: STRING exp: DYNAMIC_LIB_EXPORT_FEATURE clist: LIST [CLASS_I] do tmp := {UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (class_field.text) if tmp /= Void and then not tmp.is_empty then tmp.to_upper clist := Eiffel_universe.compiled_classes_with_name (tmp) if not clist.is_empty then cl := clist.first.compiled_class end end tmp := {UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (feature_field.text) if cl /= Void and then cl.has_feature_table and then not tmp.is_empty then tmp.to_lower f := cl.feature_with_name (tmp) tmp := {UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (creation_combo.selected_item.text) if not tmp.is_empty then tmp.to_lower cr := cl.feature_with_name (tmp) end end al := {UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (alias_field.text) if is_windows then ind := index_field.value cc := {UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (call_combo.selected_item.text) end if not valid_export_parameters (cl, cr, f, al, ind, cc) then if cl = Void then prompts.show_error_prompt (Warning_messages.w_Not_a_compiled_class (class_field.text), properties_dialog, Void) elseif not valid_class (cl) then prompts.show_error_prompt (Warning_messages.w_Class_cannot_export, properties_dialog, Void) elseif f = Void then prompts.show_error_prompt (Warning_messages.w_No_exported_feature (feature_field.text, class_field.text), properties_dialog, Void) elseif not valid_feature (f, cl) then prompts.show_error_prompt (Warning_messages.w_Feature_cannot_be_exported, properties_dialog, Void) elseif not valid_creation_routine (cr, cl) then prompts.show_error_prompt (Warning_messages.w_No_valid_creation_routine, properties_dialog, Void) elseif not al.is_empty and then not valid_alias (al) then prompts.show_error_prompt (Warning_messages.w_Invalid_alias, properties_dialog, Void) elseif is_windows and then ind /= 0 and then not valid_index (ind) then prompts.show_error_prompt (Warning_messages.w_Invalid_index, properties_dialog, Void) else prompts.show_error_prompt (Warning_messages.w_Invalid_parameters, properties_dialog, Void) end else -- Ah we can create a new exported feature. create exp.make (cl, cr, f) if not al.is_empty then exp.set_alias_name (al) end if is_windows then if ind /= 0 then exp.set_index (ind) end if not default_calling_convention.same_string_general (cc) then exp.set_call_type (cc) end else exp.remove_index exp.remove_call_type end exports.extend (exp) changed := True properties_dialog.destroy refresh_list end end new_class_name (is_enter_pressed: BOOLEAN) -- A new class name was entered in `class_field'. -- Update the creation routines list if possible. require really_creating: valid_properties_dialog local cl: CLASS_C tmp: STRING cit: EV_LIST_ITEM clist: LIST [CLASS_I] do creation_combo.wipe_out tmp := {UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (class_field.text) if not tmp.is_empty then tmp.to_upper clist := Eiffel_universe.compiled_classes_with_name (tmp) if not clist.is_empty then cl := clist.first.compiled_class end end if cl = Void then -- The entered class does not exist or is not compiled. create cit.make_with_text (Warning_messages.w_Not_a_compiled_class_line (tmp)) creation_combo.extend (cit) elseif not valid_class (cl) then -- The entered class name is invalid. create cit.make_with_text (Warning_messages.w_Class_cannot_export) creation_combo.extend (cit) else class_field.set_text (cl.name_in_upper) -- Fill in `creation_combo' with the list of valid creation routines of `cl'. available_creation_routines := valid_creation_routines (cl) if not available_creation_routines.is_empty then from available_creation_routines.start until available_creation_routines.after loop create cit.make_with_text (available_creation_routines.item.name_32) creation_combo.extend (cit) available_creation_routines.forth end if is_enter_pressed then feature_field.set_focus end else -- The entered class has no valid creation routine. create cit.make_with_text (Warning_messages.W_no_valid_creation_routine) creation_combo.extend (cit) end end end properties_dialog: EV_DIALOG -- Dialog used to alter the status of exported features (and to add new features). class_field: EV_TEXT_FIELD -- Field containing the class name --| (only valid if a `new feature' dialog has been created, not if a modification dialog was created). feature_field: EV_TEXT_FIELD -- Field containing the feature name --| (only valid if a `new feature' dialog has been created, not if a modification dialog was created). creation_combo: EV_COMBO_BOX -- Combo box containing the selected creation routine name. alias_field: EV_TEXT_FIELD -- Text field containing the (optional) alias name. index_field: EV_SPIN_BUTTON -- Spin button containing the (optional) index. call_combo: EV_COMBO_BOX -- Combo box containing the chosen (optional) calling convention. okb: EV_BUTTON -- `OK' button for the properties dialog. available_creation_routines: LIST [E_FEATURE] -- List of valid creation routines displayed in the properties dialog. modified_exported_feature: DYNAMIC_LIB_EXPORT_FEATURE -- A reference to the exported feature being modified. feature {NONE} -- Implementation: checks valid_exported_feature (exp: DYNAMIC_LIB_EXPORT_FEATURE): BOOLEAN -- Is `exp' a valid export feature? do Result := valid_export_parameters (exp.compiled_class, exp.creation_routine, exp.routine, exp.alias_name, exp.index, exp.call_type) end valid_export_parameters (cl: CLASS_C; cr: E_FEATURE; f: E_FEATURE; al: STRING; ind: INTEGER; cc: STRING): BOOLEAN -- Is the export feature defined by these parameters valid? -- `cl': its class, `cr': the creation routine, `f': the exported feature, -- `ind': the index, `al': an alias name, `cc': the calling convention. do Result := valid_class (cl) and then -- At least a feature must be declared, -- but a creation is not necessary (the feature might be a creation routine). f /= Void and then (cr /= Void implies valid_creation_routine (cr, cl)) and then (cr = Void implies valid_creation_routine (f, cl)) and then valid_feature (f, cl) and then -- All other parameters are optional. (ind /= 0 implies ind > 0) and then ((al /= Void and then not al.is_empty) implies valid_alias (al)) and then ((cc /= Void and then not cc.is_empty) implies valid_calling_convention (cc)) end conflicting_exports: BOOLEAN -- Do some exported features present conflicts? -- It may be the case if the exported names are similar, or if indices are similar. local exp: DYNAMIC_LIB_EXPORT_FEATURE cur: CURSOR oa: STRING do from exports.start until exports.after or Result loop exp := exports.item cur := exports.cursor from exports.forth until exports.after or Result loop oa := exports.item.exported_name if -- Two indices are similar. exports.item.index /= 0 and exports.item.index = exp.index or else -- Two exported names are similar. oa /= Void and then oa.same_string_general (exp.exported_name) then Result := True end exports.forth end exports.go_to (cur) exports.forth end end export_definition_problem: INTEGER -- Does `Current' represent a valid definition file? -- All exported features must be valid, and there must be no conflict. -- Return the index of an invalid exported feature if there is an invalid feature, -- -1 if there is a conflict, 0 if everything is ok. do from exports.start Result := 0 until exports.after or Result /= 0 loop if not valid_exported_feature (exports.item) then Result := exports.index end exports.forth end if Result = 0 and then conflicting_exports then Result := -1 end end valid_class (c: CLASS_C): BOOLEAN -- Is `c' a valid class to export to a dynamic library? do Result := c /= void and then c.has_feature_table and then not c.is_deferred and then c.generics = Void end valid_creation_routine (f: E_FEATURE; cl: CLASS_C): BOOLEAN -- Is `f' a valid creation routine for `cl'? require valid_class: valid_class (cl) do Result := f /= Void and then not f.has_arguments and then cl.valid_creation_procedure_32 (f.name_32) and then f.is_procedure end valid_feature (f: E_FEATURE; cl: CLASS_C): BOOLEAN -- Is `f' a valid feature to export for `cl'? require valid_current_class: valid_class (cl) do Result := f /= Void and then cl.feature_table.has_feature_named (f) and then not f.is_attribute and then not f.is_deferred and then not f.is_external end valid_alias (al: STRING): BOOLEAN -- Is `al' a valid alias? do Result := (create {EIFFEL_SYNTAX_CHECKER}).is_valid_identifier (al) end valid_index (i: INTEGER): BOOLEAN -- Is `i' a valid integer to be an index in a dynamic library? do Result := i > 0 end valid_calling_convention (cc: STRING): BOOLEAN -- Is `cc' a valid calling convention? do Result := valid_calling_conventions.has (cc) end valid_calling_conventions: LIST [STRING] -- Supported valid calling conventions. --| Only support the VC++ calling conventions, since this tool doesn't generate DLL's for Borland, --| and the calling convention has no meaning for this tool on Unix systems. once create {ARRAYED_LIST [STRING]} Result.make (3) Result.compare_objects Result.extend (default_calling_convention) Result.extend ("__fastcall") Result.extend ("__stdcall") end default_calling_convention: STRING = "__cdecl" -- Default calling convention when none is specified. invariant exports_exist: exports /= Void exports_list_exists: exports_list /= Void graphical_synchronization_ok: exports_list.count = exports.count note ca_ignore: "CA093", "CA093: manifest array type mismatch" copyright: "Copyright (c) 1984-2020, 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