note description: "Window manager for tools." legal: "See notice at end of class." status: "See notice at end of class." date: "$Date$" revision: "$Revision$" class EB_WINDOW_MANAGER inherit ANY EB_SHARED_INTERFACE_TOOLS export {NONE} all end EB_CONSTANTS export {NONE} all end SHARED_EIFFEL_PROJECT export {NONE} all end EB_CLUSTER_MANAGER_OBSERVER -- Just to have a reference to the cluster manager. export {NONE} all redefine on_project_loaded, on_project_unloaded end PROJECT_CONTEXT export {NONE} all end EB_SHARED_GRAPHICAL_COMMANDS export {NONE} all end EV_SHARED_APPLICATION export {NONE} all end ES_SHARED_DIALOG_BUTTONS export {NONE} all end create make feature {NONE} -- Initialization make -- Make a window manager. do create managed_windows.make (10) create focused_windows.make (5) create minimize_all_cmd.make minimize_all_cmd.set_pixmap (pixmaps.icon_pixmaps.windows_minimize_all_icon) minimize_all_cmd.set_tooltip (Interface_names.e_Minimize_all) minimize_all_cmd.set_menu_name (Interface_names.m_Minimize_all) minimize_all_cmd.set_tooltext (Interface_names.b_Minimize_all) minimize_all_cmd.set_name ("Minimize_all") minimize_all_cmd.add_agent (agent minimize_all) minimize_all_cmd.enable_sensitive create raise_all_cmd.make raise_all_cmd.set_pixmap (pixmaps.icon_pixmaps.windows_raise_all_icon) raise_all_cmd.set_tooltip (Interface_names.e_Raise_all) raise_all_cmd.set_menu_name (Interface_names.m_Raise_all) raise_all_cmd.set_tooltext (Interface_names.b_Raise_all) raise_all_cmd.set_name ("Raise_all") raise_all_cmd.add_agent (agent raise_all) raise_all_cmd.enable_sensitive create raise_all_unsaved_cmd.make raise_all_unsaved_cmd.set_pixmap (pixmaps.icon_pixmaps.windows_raise_all_unsaved_icon) raise_all_unsaved_cmd.set_tooltip (Interface_names.e_Raise_all_unsaved) raise_all_unsaved_cmd.set_menu_name (Interface_names.m_Raise_all_unsaved) raise_all_unsaved_cmd.set_name ("Raise_all_unsaved") raise_all_unsaved_cmd.add_agent (agent raise_all_unsaved) raise_all_unsaved_cmd.enable_sensitive Eiffel_project.manager.load_agents.extend (agent on_project_loaded) Eiffel_project.manager.create_agents.extend (agent on_project_created) Eiffel_project.manager.close_agents.extend (agent on_project_unloaded) initialize_prettify_suggestion_detector end feature -- Basic operations new_menu: EB_WINDOW_MANAGER_MENU -- Menu corresponding to current: This is a menu with -- the following entries: New Window, Minimize All and -- an entry for each opened window. -- -- When this menu is not anymore needed, call `recycle' on it. do create Result.make (Current) end new_widget: EB_WINDOW_MANAGER_LIST -- Widget corresponding to current: This is a list with -- all opened windows. -- -- When this list is not anymore needed, call `recycle' on it. do create Result.make (Current) end create_window -- Create a new development window and update `last_created_window'. local l_director: EB_DEVELOPMENT_WINDOW_DIRECTOR do create l_director.make l_director.construct initialize_window (l_director.develop_window, True) end load_window_session_data (a_dev_window: EB_DEVELOPMENT_WINDOW) -- Load `a_dev_window''s session data. -- If `a_dev_window' is void, a new development window will be created. local l_director: EB_DEVELOPMENT_WINDOW_DIRECTOR do create l_director.make l_director.construct_with_session_data (a_dev_window) initialize_window (l_director.develop_window, False) end initialize_window (a_window: EB_DEVELOPMENT_WINDOW; a_new_window: BOOLEAN) -- Initialize `a_window'. -- If `a_window' is not `a_new_window', we ignore window title. require a_window_not_void: a_window /= Void do managed_windows.extend (a_window) if a_window.stone = Void and then a_new_window then -- Set the title if a stone hasn't already been set by session manager. a_window.set_title (new_title) end if a_new_window then notify_observers (a_window, Notify_added_window) else notify_observers (a_window, Notify_changed_window) end last_created_window := a_window -- Show the window if not already shown if not a_window.is_visible then a_window.show end a_window.give_focus end create_dynamic_lib_window -- Create a new dynamic library window if necessary and display it. local a_window: EB_DYNAMIC_LIB_WINDOW do if not dynamic_lib_window_is_valid then create a_window.make managed_windows.extend (a_window) notify_observers (a_window, Notify_added_window) set_dynamic_lib_window (a_window) end -- Show the window dynamic_lib_window.show dynamic_lib_window.give_focus ensure valid_dynamic_lib_window: dynamic_lib_window_is_valid end feature -- Access development_windows_with_class (a_class: CLASS_I): LIST [EB_DEVELOPMENT_WINDOW] -- List of all windows with `cl_name' opened. require a_class_not_void: a_class /= Void local l_index: INTEGER do create {ARRAYED_LIST [EB_DEVELOPMENT_WINDOW]} Result.make (managed_windows.count) from l_index := managed_windows.index managed_windows.start until managed_windows.after loop if attached {EB_DEVELOPMENT_WINDOW} managed_windows.item as a_dev and then a_dev.editors_manager.is_class_editing (a_class) then Result.extend (a_dev) end managed_windows.forth end managed_windows.go_i_th (l_index) ensure not_void: Result /= Void end compile_start_actions: ACTION_SEQUENCE [TUPLE] -- Actions to be performed when Eiffel compilation starts do if compile_start_actions_internal = Void then create compile_start_actions_internal end Result := compile_start_actions_internal ensure result_attached: Result /= Void end windows: BILINEAR [EB_WINDOW] -- All development windows managed by Current do Result := managed_windows.twin ensure result_attached: Result /= Void end development_windows: attached ARRAYED_LIST [EB_DEVELOPMENT_WINDOW] -- All development windows managed by Current local l_windows: like managed_windows do from l_windows := managed_windows.twin l_windows.start create Result.make (l_windows.count) until l_windows.after loop if attached {EB_DEVELOPMENT_WINDOW} l_windows.item as lt_dev_window then Result.extend (lt_dev_window) end l_windows.forth end end feature {EB_SHARED_INTERFACE_TOOLS, EB_COMMAND} -- Access all_modified_classes: ARRAYED_LIST [CLASS_I] -- Retrieves a list of all modified classes local l_index: INTEGER do create Result.make (0) from l_index := managed_windows.index managed_windows.start until managed_windows.after loop if attached {EB_DEVELOPMENT_WINDOW} managed_windows.item as a_dev and then not a_dev.is_recycled and then a_dev.editors_manager.changed then Result.append (a_dev.editors_manager.changed_classes) end managed_windows.forth end managed_windows.go_i_th (l_index) end feature -- Status report last_created_window: EB_DEVELOPMENT_WINDOW -- Window created by the last call to `create_window'. -- Void if none. development_windows_count: INTEGER -- number of visible development windows local l_index: INTEGER do from l_index := managed_windows.index managed_windows.start until managed_windows.after loop if attached {EB_DEVELOPMENT_WINDOW} managed_windows.item then Result := Result + 1 end managed_windows.forth end managed_windows.go_i_th (l_index) end has_active_development_windows: BOOLEAN -- Are there any active development window up? do Result := development_windows_count /= 0 end has_modified_windows: BOOLEAN -- Are there any window having been modified and not yet saved? local l_index: INTEGER do from l_index := managed_windows.index managed_windows.start until Result or else managed_windows.after loop if attached {EB_DEVELOPMENT_WINDOW} managed_windows.item as a_dev then Result := a_dev.any_editor_changed end managed_windows.forth end if not Result then Result := dynamic_lib_window_is_valid and then dynamic_lib_window.changed end managed_windows.go_i_th (l_index) end development_window_from_window (a_window: EV_WINDOW): detachable EB_DEVELOPMENT_WINDOW -- Return the development window whose widget is `a_window'. local l_index: INTEGER do from l_index := managed_windows.index managed_windows.start until managed_windows.after or else Result /= Void loop if managed_windows.item /= Void and then managed_windows.item.window = a_window and then attached {EB_DEVELOPMENT_WINDOW} managed_windows.item as dev then Result := dev end managed_windows.forth end managed_windows.go_i_th (l_index) end last_focused_development_window: detachable EB_DEVELOPMENT_WINDOW -- Return the development window which last had the keyboard focus. do from focused_windows.finish until Result /= Void or else focused_windows.before loop if attached {EB_DEVELOPMENT_WINDOW} focused_windows.item as dev then Result := dev end focused_windows.back end if Result = Void then Result := a_development_window end end last_focused_window: detachable EB_WINDOW -- Return the window which last had the keyboard focus. -- Return Void if no window is focused. do if not focused_windows.is_empty then Result := focused_windows.last elseif not managed_windows.is_empty then Result := managed_windows.last end end a_development_window: detachable EB_DEVELOPMENT_WINDOW -- Return a random development window local l_index: INTEGER do from l_index := managed_windows.index managed_windows.start until managed_windows.after or Result /= Void loop if attached {EB_DEVELOPMENT_WINDOW} managed_windows.item as dev then Result := dev end managed_windows.forth end managed_windows.go_i_th (l_index) end feature -- Query development_window_from_id (a_window_id: NATURAL_32): EB_DEVELOPMENT_WINDOW -- Retrieve a development window using a window id matched to {EB_DEVELOPMENT_WINDOW}.window_id require a_window_id_positive: a_window_id > 0 local l_windows: like managed_windows i: INTEGER do l_windows := managed_windows i := l_windows.index from l_windows.start until l_windows.after or Result /= Void loop if attached {like development_window_from_id} l_windows.item as res then Result := res end if Result /= Void and then Result.window_id /= a_window_id then Result := Void l_windows.forth end end l_windows.go_i_th (i) end active_editor_for_class (a_class: CLASS_I): detachable EB_SMART_EDITOR -- Attempts to retrieve the most applicable editor for a given class. -- -- `a_class': The class to retrieve the most applicable editor for. -- `Result': An editor which the supplied class is edited using, or Void if not being edited. require a_class_attached: a_class /= Void local l_editor: EB_SMART_EDITOR l_editors: DS_ARRAYED_LIST [EB_SMART_EDITOR] do l_editors := active_editors_for_class (a_class) if not l_editors.is_empty then from l_editors.start until l_editors.after loop l_editor := l_editors.item_for_iteration if Result = Void then Result := l_editor elseif l_editor.text_displayed.is_modified then -- Use modified version Result := l_editor end l_editors.forth end end end active_editors_for_class (a_class: CLASS_I): attached DS_ARRAYED_LIST [EB_SMART_EDITOR] -- Retrieves all applicable editors for a given class. -- -- `a_class': The class to retrieve the most applicable editors for. -- `Result': A list of editors editing the supplied class. require a_class_attached: a_class /= Void do create Result.make_default if attached windows as l_windows then from l_windows.start until l_windows.after loop if attached {EB_DEVELOPMENT_WINDOW} l_windows.item_for_iteration as l_dev_window and then attached l_dev_window.editors_manager as l_editor_manager and then attached l_editor_manager.editor_editing (a_class) as l_editors then across l_editors as e loop Result.force_last (e.item) end end l_windows.forth end end ensure result_contains_attached_items: not Result.has (Void) end feature -- Actions on a given window show_window (a_window: EB_WINDOW) -- Show the window. do -- We call `raise' since it takes care of really showing the window -- in case it is hidden or minimized. a_window.window.raise notify_observers (a_window, Notify_shown_window) end hide_window (a_window: EB_WINDOW) -- Hide the window do a_window.window.hide notify_observers (a_window, Notify_hidden_window) end destroy_window (a_window: EB_WINDOW) -- Destroy the window. do -- Remove this window from managed windows. managed_windows.prune_all (a_window) focused_windows.prune_all (a_window) if last_created_window = a_window then last_created_window := Void end -- Notify the observers notify_observers (a_window, Notify_removed_window) -- Destroy the window. a_window.destroy_imp end record_window_change (a_window: EB_WINDOW) -- Record that `a_window' has changed and notify the observers. do notify_observers (a_window, Notify_changed_window) end feature -- Actions on all windows raise_all_unsaved -- Raise all the editors. do for_all (agent raise_unsaved_action) end refresh_all -- Refresh all the windows after a compilation do for_all (agent refresh_action) end save_all -- Ask each window to save its content. do for_all (agent save_action) end save_all_before_compiling -- Ask each window to save its content. do for_all (agent save_before_compiling_action) end backup_all -- Create a backup file (.swp) for all development window. do not_backuped := 0 for_all (agent backup_action) end not_backuped: INTEGER -- Number of files that could not be backed up during a back up. minimize_all -- Minimize all windows do for_all (agent minimize_action) end disable_all -- Disable sensitivity on all windows. do for_all (agent disable_action) end enable_all -- Enable sensitivity on all windows. do for_all (agent enable_action) end quick_refresh_all_margins -- Redraws the margins of all the editor windows. do for_all (agent quick_refresh_margin_action) end quick_refresh_all_editors -- Redraws the editors of all the windows. do for_all (agent quick_refresh_action) end raise_all -- Raise all windows. do for_all (agent show_window) end close_all -- Close all windows. local l_snapshot: like managed_windows do from l_snapshot := managed_windows.twin l_snapshot.start until l_snapshot.after loop close_action (l_snapshot.item) l_snapshot.forth end end synchronize_all_about_breakpoints do quick_refresh_all_margins for_all (agent synchronize_breakpoints_action) end synchronize_all -- A compilation is over. Warn all windows and tools. do -- Reload the cluster tree in the cluster manager. manager.refresh -- Get rid of all dead classes in the favorites. favorites.refresh -- Update the state of some commands. if not Eiffel_project.compilation_modes.is_precompiling then freeze_project_cmd.enable_sensitive precompilation_cmd.disable_sensitive Finalize_project_cmd.enable_sensitive else freeze_project_cmd.disable_sensitive precompilation_cmd.enable_sensitive Finalize_project_cmd.disable_sensitive end for_all (agent c_compilation_start_action) melt_project_cmd.enable_sensitive terminate_c_compilation_cmd.disable_sensitive refactoring_manager.enable_sensitive discover_melt_cmd.enable_sensitive analyze_cmd.enable_sensitive analyze_editor_cmd.update_sensitive analyze_parent_cmd.update_sensitive analyze_target_cmd.update_sensitive project_cancel_cmd.disable_sensitive clean_compile_project_cmd.enable_sensitive if process_manager.is_c_compilation_running then on_c_compilation_start else for_all (agent for_all (agent c_compilation_stop_action)) end for_all (agent synchronize_action) end synchronize_all_favorites_tool -- Synchronize all Favorites tool do for_all (agent (a_window: EB_WINDOW) do if attached {EB_DEVELOPMENT_WINDOW} a_window as l_win and then attached l_win.favorites_manager as l_fav then l_fav.refresh end end ) end display_message_and_percentage (m: READABLE_STRING_GENERAL; a_value: INTEGER) -- Display message `m' and `a_value' percentage in status bars of all development windows. require one_line_message: m /= Void and then (not m.has_code (('%N').natural_32_code) and not m.has_code (('%R').natural_32_code)) a_value_valid: a_value >= 0 and then a_value <= 100 local l_managed_windows: like managed_windows l_status_bar: EB_DEVELOPMENT_WINDOW_STATUS_BAR do from -- Make a twin of the list incase window is destroyed during -- indirect call to status bar `process_events_and_idle' which -- is needed to update the label and progress bar display. l_managed_windows := managed_windows.twin l_managed_windows.start until l_managed_windows.after loop if attached {EB_DEVELOPMENT_WINDOW} l_managed_windows.item as cv_dev and then not cv_dev.destroyed then l_status_bar := cv_dev.status_bar l_status_bar.display_message (m) l_status_bar.progress_bar.reset l_status_bar.progress_bar.set_value (a_value) end l_managed_windows.forth end end display_message (m: READABLE_STRING_GENERAL) -- Display a message in status bars of all development windows. require one_line_message: m /= Void and then (not m.has_code (('%N').natural_32_code) and not m.has_code (('%R').natural_32_code)) local l_managed_windows: like managed_windows do from -- Make a twin of the list incase window is destroyed during -- indirect call to status bar `process_events_and_idle' which -- is needed to update the label and progress bar display. l_managed_windows := managed_windows.twin l_managed_windows.start until l_managed_windows.after loop if attached {EB_DEVELOPMENT_WINDOW} l_managed_windows.item as cv_dev and then not cv_dev.destroyed then cv_dev.status_bar.display_message (m) end l_managed_windows.forth end end display_percentage (a_value: INTEGER) -- Display `a_value' percentage in status bars of all development windows. require a_value_valid: a_value >= 0 and then a_value <= 100 local l_managed_windows: like managed_windows pb: EB_PERCENT_PROGRESS_BAR do from -- Make a twin of the list incase window is destroyed during -- indirect call to status bar `process_events_and_idle' which -- is needed to update the label and progress bar display. l_managed_windows := managed_windows.twin l_managed_windows.start until l_managed_windows.after loop if attached {EB_DEVELOPMENT_WINDOW} l_managed_windows.item as cv_dev and then not cv_dev.destroyed then pb := cv_dev.status_bar.progress_bar pb.reset pb.set_value (a_value) pb.refresh_now end l_managed_windows.forth end end display_c_compilation_progress (mess: STRING_GENERAL) -- Display `mess' in status bars of all development windows. require mess_not_void: mess /= Void mess_not_empty: not mess.is_empty local l_managed_windows: like managed_windows do from -- Make a twin of the list incase window is destroyed during -- indirect call to status bar `process_events_and_idle' which -- is needed to update the label and progress bar display. l_managed_windows := managed_windows.twin l_managed_windows.start until l_managed_windows.after loop if attached {EB_DEVELOPMENT_WINDOW} l_managed_windows.item as cv_dev and then not cv_dev.destroyed then if cv_dev.status_bar.message.is_empty then cv_dev.status_bar.display_message (mess) state_message_waiting_count := 0 else state_message_waiting_count := state_message_waiting_count + 1 if state_message_waiting_count > max_waiting_count then state_message_waiting_count := 0 cv_dev.status_bar.display_message (mess) end end end l_managed_windows.forth end end for_all_development_windows (p: PROCEDURE [EB_DEVELOPMENT_WINDOW]) -- Call `p' on all development windows. local l_index: INTEGER do from l_index := managed_windows.index managed_windows.start until managed_windows.after loop if attached {EB_DEVELOPMENT_WINDOW} managed_windows.item as cv_dev then p.call ([cv_dev]) end managed_windows.forth end if managed_windows.valid_index (l_index) then managed_windows.go_i_th (l_index) end end feature {EB_SHORTCUT_MANAGER} -- Actions on all windows refresh_commands -- Refresh all windows commands. do for_all (agent refresh_commands_action) end refresh_external_commands -- Only refresh external commands do for_all (agent refresh_external_commands_action) end feature {EB_WINDOW, EB_DEVELOPMENT_WINDOW_BUILDER} -- Events set_focused_window (w: EB_WINDOW) -- Tell `Current' `w' has been given the focus. do focused_windows.prune_all (w) focused_windows.extend (w) end try_to_destroy_window (a_window: EB_WINDOW) -- Destroy the window if it is possible. -- The window-level checks should be performed in `{EB_WINDOW}.destroy`. -- This method only takes into account the cases when closing the -- window means exiting the application. do if development_windows_count = 1 and then attached {EB_DEVELOPMENT_WINDOW} a_window then confirm_and_quit else if attached {EB_DEVELOPMENT_WINDOW} a_window as loc_development_window then loc_development_window.save_window_data end destroy_window (a_window) end end feature {NONE} -- Exit implementation confirm_and_quit -- If a compilation is under way, do not exit. local l_exit_save_prompt: ES_SAVE_CLASSES_PROMPT l_warning: ES_WARNING_PROMPT l_classes: DS_ARRAYED_LIST [CLASS_I] l_exit: BOOLEAN do if Eiffel_project.initialized and then Eiffel_project.is_compiling then create l_warning.make_standard_with_cancel (warning_messages.w_exiting_stops_compilation) l_warning.set_button_text ({ES_DIALOG_BUTTONS}.ok_button, interface_names.b_force_exit) l_warning.set_button_icon ({ES_DIALOG_BUTTONS}.ok_button, pixmaps.icon_pixmaps.general_warning_icon) l_warning.set_button_text ({ES_DIALOG_BUTTONS}.cancel_button, interface_names.b_ok) l_warning.show_on_active_window l_exit := l_warning.dialog_result = {ES_DIALOG_BUTTONS}.ok_button else l_exit := True end if l_exit then if has_modified_windows then exit_application_cmd.set_already_confirmed (True) create l_classes.make_default all_modified_classes.do_all (agent l_classes.force_last) create l_exit_save_prompt.make_standard_with_cancel (interface_names.l_exit_warning) l_exit_save_prompt.classes := l_classes l_exit_save_prompt.set_button_action (l_exit_save_prompt.dialog_buttons.yes_button, agent save_and_quit) l_exit_save_prompt.set_button_action (l_exit_save_prompt.dialog_buttons.no_button, agent quit) l_exit_save_prompt.show_on_active_window else quit end end end kill_process_and_confirm_quit -- Kill running c compilation and external command, if any and then quit. do process_manager.terminate_process quit end save_and_quit -- Save all windows and destroy the last development window. do save_all -- Exit only when all windows have been saved. if not has_modified_windows then quit end end quit -- Destroy the last development window. do if process_manager.is_process_running then process_manager.confirm_process_termination_for_quiting (agent kill_process_and_confirm_quit, Void, last_focused_development_window.window) else Exit_application_cmd.ask_confirmation end end feature -- Prettify suggestion initialize_prettify_suggestion_detector do create prettify_suggestion_detector prettify_suggestion_detector.install end prettify_suggestion_detector: ES_PRETTIFY_SUGGESTION_DETECTOR feature -- Access: session data load_favorites -- Try to initialize the favorites with the session data. local retried: BOOLEAN do -- Give up if loading favorites has failed. if not retried then if favorites_storage = Void then create favorites_storage end if attached favorites_storage.data_from_storage as l_data then favorites.make_with_string (l_data) if favorites.loading_error then favorites_storage.store_data (Void) end end end rescue retried := True retry end save_favorites -- Try to save the favorites' state within the session data. local retried: BOOLEAN do if not retried then if favorites_storage = Void then create favorites_storage end favorites_storage.store_data (favorites.string_representation) end rescue retried := True retry end load_session -- Try to recreate previous project session, if any. local l_i, l_window_count: INTEGER l_retried: BOOLEAN l_managed_windows: like managed_windows l_dev_window: EB_DEVELOPMENT_WINDOW do check system_defined: eiffel_project.system_defined end if not l_retried then -- Attempt to load the 'session.wb' file from the project directory. -- If load fails then do nothing. -- Recreate previous session from retrieved session data. -- Remove any existing managed windows. from l_managed_windows := managed_windows.twin l_managed_windows.start until l_managed_windows.after loop if l_managed_windows.item /= Void then if attached {EB_DYNAMIC_LIB_WINDOW} l_managed_windows.item as l_dl_window then destroy_window (l_dl_window) end if l_dev_window = Void and then attached {EB_DEVELOPMENT_WINDOW} l_managed_windows.item as dev then l_dev_window := dev end end l_managed_windows.forth end check at_least_one_develop_window: l_dev_window /= Void end if attached {INTEGER_32_REF} l_dev_window.project_session_data.value (l_dev_window.development_window_data.development_window_count_id) as l_window_count_ref then l_window_count := l_window_count_ref.item end if l_window_count = 0 then -- At least one l_window_count := 1 end from l_managed_windows := managed_windows.twin if l_managed_windows.valid_cursor_index (l_window_count + 1) then l_managed_windows.go_i_th (l_window_count + 1) else l_managed_windows.go_i_th (l_managed_windows.index + 1) end -- Only destroy extra windows until l_managed_windows.after loop destroy_window (l_managed_windows.item) l_managed_windows.forth end from l_i := 1 l_managed_windows.start until l_i > l_window_count loop if not l_managed_windows.after then if attached {EB_DEVELOPMENT_WINDOW} l_managed_windows.item as dev then l_dev_window := dev load_window_session_data (dev) else check is_dev_window: False end end l_managed_windows.forth else load_window_session_data (Void) end l_i := l_i + 1 end end rescue l_retried := True retry end save_session -- Try to store current session data. local retried: BOOLEAN l_develop_window: EB_DEVELOPMENT_WINDOW do check system_defined: eiffel_project.system_defined end if not retried then -- Attempt to save the 'session.wb' file to the current project directory. -- If save cannot be made then do nothing. l_develop_window := a_development_window if l_develop_window /= Void then -- Maybe we can't save development window count data in `project_session_data' or `session_data' since they are all *window* related data? l_develop_window.project_session_data.set_value (development_windows_count, l_develop_window.development_window_data.development_window_count_id) end for_all_development_windows (agent (a_develop_window: EB_DEVELOPMENT_WINDOW) require not_void: a_develop_window /= Void do a_develop_window.project_session_data.set_value ( a_develop_window.save_layout_to_session, a_develop_window.development_window_data.development_window_project_data_id) end) end rescue retried := True retry end feature {NONE} -- Implementation: session data favorites_storage: FAVORITES_STORAGE -- Favorites' storage feature -- Events on_compile -- A compilation has been launched. -- Update the display accordingly, ie gray out all forbidden commands. do Melt_project_cmd.disable_sensitive Freeze_project_cmd.disable_sensitive Finalize_project_cmd.disable_sensitive Precompilation_cmd.disable_sensitive Project_cancel_cmd.enable_sensitive discover_melt_cmd.disable_sensitive analyze_cmd.disable_sensitive analyze_editor_cmd.disable_sensitive analyze_parent_cmd.disable_sensitive analyze_target_cmd.disable_sensitive refactoring_manager.disable_sensitive for_all (agent c_compilation_start_action) compile_start_actions.call (Void) end on_refactoring_start -- A refactoring has been started. do Melt_project_cmd.disable_sensitive Freeze_project_cmd.disable_sensitive Finalize_project_cmd.disable_sensitive Precompilation_cmd.disable_sensitive discover_melt_cmd.disable_sensitive analyze_cmd.disable_sensitive analyze_editor_cmd.disable_sensitive analyze_parent_cmd.disable_sensitive analyze_target_cmd.disable_sensitive for_all (agent c_compilation_start_action) end on_refactoring_end -- A refactoring has finished. do Melt_project_cmd.enable_sensitive Freeze_project_cmd.enable_sensitive Finalize_project_cmd.enable_sensitive Precompilation_cmd.enable_sensitive discover_melt_cmd.enable_sensitive analyze_cmd.enable_sensitive analyze_editor_cmd.update_sensitive analyze_parent_cmd.update_sensitive analyze_target_cmd.update_sensitive for_all (agent c_compilation_stop_action) end on_c_compilation_start -- Freezing or finalizing has been launched. -- Update the display accordingly, ie gray out all forbidden commands. do Freeze_project_cmd.disable_sensitive Finalize_project_cmd.disable_sensitive terminate_c_compilation_cmd.enable_sensitive for_all (agent c_compilation_start_action) run_workbench_cmd.disable_sensitive if process_manager.is_finalizing_running then run_finalized_cmd.disable_sensitive end end on_c_compilation_stop -- Freezing or finalizing has finished. -- Update the display accordingly. do Freeze_project_cmd.enable_sensitive Finalize_project_cmd.enable_sensitive terminate_c_compilation_cmd.disable_sensitive for_all (agent c_compilation_stop_action) run_workbench_cmd.enable_sensitive run_finalized_cmd.enable_sensitive end on_project_created -- A new project has been created. Update the state of some commands. do Melt_project_cmd.enable_sensitive Freeze_project_cmd.enable_sensitive Finalize_project_cmd.enable_sensitive Precompilation_cmd.enable_sensitive clean_compile_project_cmd.enable_sensitive System_cmd.enable_sensitive System_information_cmd.enable_sensitive discover_melt_cmd.enable_sensitive analyze_cmd.enable_sensitive analyze_editor_cmd.update_sensitive analyze_parent_cmd.update_sensitive analyze_target_cmd.update_sensitive source_control_cmd.update_sensitive for_all (agent create_project_action) end on_project_loaded -- A new project has been loaded. Warn all managed windows. do if Eiffel_project.initialized then if Eiffel_project.compilation_modes.is_precompiling then Melt_project_cmd.disable_sensitive Freeze_project_cmd.disable_sensitive Finalize_project_cmd.disable_sensitive Precompilation_cmd.enable_sensitive Run_project_cmd.disable_sensitive Run_workbench_cmd.disable_sensitive Run_finalized_cmd.disable_sensitive discover_melt_cmd.disable_sensitive else Melt_project_cmd.enable_sensitive Freeze_project_cmd.enable_sensitive Finalize_project_cmd.enable_sensitive Precompilation_cmd.disable_sensitive Run_project_cmd.enable_sensitive Run_workbench_cmd.enable_sensitive Run_finalized_cmd.enable_sensitive discover_melt_cmd.enable_sensitive end analyze_cmd.enable_sensitive analyze_editor_cmd.update_sensitive analyze_parent_cmd.update_sensitive analyze_target_cmd.update_sensitive source_control_cmd.update_sensitive clean_compile_project_cmd.enable_sensitive System_cmd.enable_sensitive System_information_cmd.enable_sensitive Export_cmd.enable_sensitive Document_cmd.enable_sensitive else Melt_project_cmd.disable_sensitive Precompilation_cmd.disable_sensitive Freeze_project_cmd.disable_sensitive Finalize_project_cmd.disable_sensitive System_cmd.disable_sensitive System_information_cmd.disable_sensitive Export_cmd.disable_sensitive Document_cmd.disable_sensitive Run_project_cmd.disable_sensitive Run_workbench_cmd.disable_sensitive Run_finalized_cmd.disable_sensitive discover_melt_cmd.disable_sensitive analyze_cmd.disable_sensitive analyze_editor_cmd.disable_sensitive analyze_parent_cmd.disable_sensitive analyze_target_cmd.disable_sensitive source_control_cmd.disable_sensitive end -- Recreate window configuration from last session of project if any. load_session load_favorites Manager.on_project_loaded for_all (agent load_project_action) end on_project_unloaded -- Current project has been closed. Warn all managed windows. do Manager.on_project_unloaded save_favorites -- Make development window session data persistent for future reloading. if eiffel_project.system_defined then save_session end for_all (agent unload_project_action) Melt_project_cmd.disable_sensitive Freeze_project_cmd.disable_sensitive Finalize_project_cmd.disable_sensitive Precompilation_cmd.disable_sensitive clean_compile_project_cmd.disable_sensitive System_cmd.disable_sensitive System_information_cmd.disable_sensitive Export_cmd.disable_sensitive Document_cmd.disable_sensitive Run_project_cmd.disable_sensitive Run_workbench_cmd.disable_sensitive Run_finalized_cmd.disable_sensitive discover_melt_cmd.disable_sensitive analyze_cmd.disable_sensitive analyze_editor_cmd.disable_sensitive analyze_parent_cmd.disable_sensitive analyze_target_cmd.disable_sensitive source_control_cmd.disable_sensitive end feature {NONE} -- Implementation exiting_application: BOOLEAN -- Is the application currently in its closing phase? --| Used in `destroy_window' to avoid infinite reentrance. focused_windows: ARRAYED_LIST [EB_WINDOW] -- Focused windows (chronological order). close_action (a_window: EB_WINDOW) -- Action to be performed on `item' in `close_all'. do destroy_window (a_window) notify_observers (a_window, Notify_removed_window) end minimize_action (a_window: EB_WINDOW) -- Action to be performed on `item' in `minimize_all'. do a_window.window.minimize end disable_action (a_window: EB_WINDOW) -- Action to be performed on `item' in `disable_all'. do a_window.window.disable_sensitive end enable_action (a_window: EB_WINDOW) -- Action to be performed on `item' in `enable_all'. do a_window.window.enable_sensitive end refresh_action (a_window: EB_WINDOW) -- Action to be performed on `item' in `refresh'. do a_window.refresh notify_observers (a_window, Notify_changed_window) end refresh_commands_action (a_window: EB_WINDOW) -- Action to be performed on `item' in `refresh_all_commands'. do a_window.refresh_all_commands end refresh_external_commands_action (a_window: EB_WINDOW) -- Action to be performed on `item' in `refresh_external_commands'. do a_window.refresh_external_commands end synchronize_breakpoints_action (a_window: EB_WINDOW) -- Action to synchronize `a_window' regarding the breakpoints data. do if attached {EB_DEVELOPMENT_WINDOW} a_window as a_dev_window then a_dev_window.tools.breakpoints_tool.synchronize end end synchronize_action (a_window: EB_WINDOW) -- Action to be performed on `item' in `refresh'. do if attached {EB_DEVELOPMENT_WINDOW} a_window as a_dev_window then a_dev_window.synchronize elseif attached {EB_DYNAMIC_LIB_WINDOW} a_window as conv_dyn then conv_dyn.synchronize else a_window.refresh end notify_observers (a_window, Notify_changed_window) end backup_action (a_window: EB_WINDOW) -- Create a backup file of the text contained in `a_window'. do if attached {EB_DEVELOPMENT_WINDOW} a_window as w then w.editors_manager.backup_all not_backuped := not_backuped + w.editors_manager.not_backuped end end quick_refresh_action (a_window: EB_WINDOW) -- Action to be performed on `a_window' in `quich_refresh_all_editors'. do if attached {EB_DEVELOPMENT_WINDOW} a_window as a_dev_window then a_dev_window.quick_refresh_editors end end quick_refresh_margin_action (a_window: EB_WINDOW) -- Action to be performed on `a_window' in `quick_refresh_all_margins'. do if attached {EB_DEVELOPMENT_WINDOW} a_window as a_dev_window then a_dev_window.quick_refresh_margins end end raise_unsaved_action (a_window: EB_WINDOW) -- Action to be performed on `item' in `raise_non_saved'. do if attached {EB_DEVELOPMENT_WINDOW} a_window as a_dev_window and then a_dev_window.changed then a_window.show end end save_action (a_window: EB_WINDOW) -- Action to be performed on `item' in `save_all'. do if attached {EB_DEVELOPMENT_WINDOW} a_window as a_dev_window and then a_dev_window.any_editor_changed then a_dev_window.save_all end if attached {EB_DYNAMIC_LIB_WINDOW} a_window as dyn_window and then dyn_window.changed then dyn_window.save end end save_before_compiling_action (a_window: EB_WINDOW) -- Action to be performed on `item' in `save_all_before_compiling'. do if attached {EB_DEVELOPMENT_WINDOW} a_window as a_dev_window and then a_dev_window.editors_manager.changed then a_dev_window.save_before_compiling end end create_project_action (a_window: EB_WINDOW) -- Action to be performed on `a_window' in `create_project'. do if attached {EB_DEVELOPMENT_WINDOW} a_window as a_dev_window then a_dev_window.agents.on_project_created end end load_project_action (a_window: EB_WINDOW) -- Action to be performed on `a_window' in `load_project'. do if attached {EB_DEVELOPMENT_WINDOW} a_window as a_dev_window then a_dev_window.agents.on_project_loaded end end unload_project_action (a_window: EB_WINDOW) -- Action to be performed on `a_window' in `unload_project'. do if attached {EB_DEVELOPMENT_WINDOW} a_window as a_dev_window then a_dev_window.agents.on_project_unloaded end end c_compilation_start_action (a_window: EB_WINDOW) -- Action to be performed on `a_window' when freezing or finalizing starts. do if attached {EB_DEVELOPMENT_WINDOW} a_window as a_dev_window then a_dev_window.agents.on_c_compilation_starts end end c_compilation_stop_action (a_window: EB_WINDOW) -- Action to be performed on `a_window' when freezing or finalizing stops. do if attached {EB_DEVELOPMENT_WINDOW} a_window as a_dev_window then a_dev_window.agents.on_c_compilation_stops end end for_all (action: PROCEDURE) -- Iterate `action' on every managed window. local l_index: INTEGER do l_index := managed_windows.index from managed_windows.start until managed_windows.after loop action.call ([managed_windows.item]) managed_windows.forth end if managed_windows.valid_index (l_index) then managed_windows.go_i_th (l_index) end end feature {EB_WINDOW_MANAGER_OBSERVER, EB_WINDOW, EB_DEVELOPMENT_WINDOW_BUILDER} -- Observer pattern add_observer (an_observer: EB_WINDOW_MANAGER_OBSERVER) -- Add `an_observer' to the list of observers for Current. require valid_observer: an_observer /= Void do if observers = Void then create observers.make (2) end observers.extend (an_observer) end remove_observer (an_observer: EB_WINDOW_MANAGER_OBSERVER) -- Remove `an_observer' from the list of observers for Current. require valid_observer: an_observer /= Void do if observers /= Void then observers.start observers.prune_all (an_observer) end end minimize_all_cmd: EB_STANDARD_CMD -- Command to minimize all windows. raise_all_cmd: EB_STANDARD_CMD -- Command to raise all windows. raise_all_unsaved_cmd: EB_STANDARD_CMD -- Command to raise all unsaved windows. feature {EB_WINDOW} -- Implementation / Observer pattern notify_observers (an_item: EB_WINDOW; item_change: INTEGER) -- Notify all observers about the change of `an_item'. require -- valid_item_change: -- item_change = Notify_removed_window or -- item_change = Notify_added_window or -- item_change = Notify_changed_window valid_item: an_item /= Void do if observers /= Void then from observers.start until observers.after loop inspect item_change when Notify_added_window then observers.item.on_item_added (an_item) when Notify_changed_window then observers.item.on_item_changed (an_item) when Notify_removed_window then observers.item.on_item_removed (an_item) when Notify_shown_window then observers.item.on_item_shown (an_item) when Notify_hidden_window then observers.item.on_item_hidden (an_item) end observers.forth end end end observers: ARRAYED_LIST [EB_WINDOW_MANAGER_OBSERVER] -- All observers for Current. feature {EB_C_COMPILER_LAUNCHER, EB_WINDOW_MANAGER_LIST, EB_WINDOW_MANAGER_MENU, EB_EXEC_FORMAT_CMD, EB_EXTERNAL_COMMANDS_EDITOR} -- Implementation managed_windows: ARRAYED_SET [EB_WINDOW] -- Managed windows. feature {EB_DEVELOPMENT_WINDOW} -- Implementation new_title: STRING_GENERAL -- Find an empty titled not yet used. local l_index: INTEGER empty_title: STRING_32 window_titles: ARRAYED_LIST [STRING_GENERAL] i: INTEGER l_found: BOOLEAN l_name, l_target_name: READABLE_STRING_32 do -- Remember the title of all windows. create window_titles.make (managed_windows.count) window_titles.compare_objects l_index := managed_windows.index from managed_windows.start until managed_windows.after loop window_titles.extend (managed_windows.item.title) managed_windows.forth end managed_windows.go_i_th (l_index) -- Look for a title not yet used. if eiffel_project.system_defined and then attached eiffel_universe.target then l_name := eiffel_system.name l_target_name := eiffel_universe.target_name elseif attached eiffel_project.workbench.lace as l_lace and then attached l_lace.conf_system as s then l_name := s.name l_target_name := l_lace.target_name end empty_title := if l_name /= Void and l_target_name /= Void then interface_names.l_empty_development_window_header (l_name, l_target_name) else interface_names.t_empty_development_window end + {STRING_32} " #" from i := 1 until l_found loop Result := empty_title + i.out if not window_titles.has (Result) then l_found := True end i := i + 1 end end stop_ev_application -- Stop `application' by killing main event loop of EiffelVision2. require no_more_development_windows: development_windows_count = 0 do ev_application.destroy end store_last_focused_window -- Store layout of last focused window so new windows may be initialized -- to match. local a_window: EB_DEVELOPMENT_WINDOW do a_window := last_focused_development_window if a_window /= Void then a_window.save_layout end end feature {EB_WINDOW} -- Implementation / Private Constants Notify_hidden_window: INTEGER = -2 -- Notification constant for `notify_observers'. Notify_removed_window: INTEGER = -1 -- Notification constant for `notify_observers'. Notify_added_window: INTEGER = 1 -- Notification constant for `notify_observers'. Notify_shown_window: INTEGER = 2 -- Notification constant for `notify_observers'. Notify_changed_window: INTEGER = 0 -- Notification constant for `notify_observers'. feature{NONE} -- Implementation state_message_waiting_count: INTEGER -- Times that we have been waiting for displaying a c compilation message. max_waiting_count: INTEGER = 30; -- Max value of `state_message_waiting_count' compile_start_actions_internal: like compile_start_actions; -- Implementation of `compile_start_actions' note ca_ignore: "CA033", "CA033: too long class" copyright: "Copyright (c) 1984-2023, 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