######################################################################## #### #### Title: ordered_choice_lister.magik #### Author: Mark Cederholm #### Last Revised: 13-Jun-2002 #### #### Notes: #### #### Allows a user to select objects in a particular order using left #### and right lists and arrow keys. #### ######################################################################## #********************************************************************** # Exemplar amd shared values #********************************************************************** remex(:ordered_choice_lister) $ _pragma(classify_level=basic, topic={editors}) ## ## ordered_choice_lister :- This object displays a list from which the ## user can select items of interest in a particular order. When a ## selection is made, this can be returned to the lister's ## model using a predefined action. ## def_slotted_exemplar( :ordered_choice_lister, { {:model, _unset}, {:action, _unset}, {:string_selector, _unset}, {:list_annotation, _unset}, {:orig_list, _unset}, {:left_list, _unset}, {:right_list, _unset}, {:items, _unset} }, :model ) $ _pragma(classify_level=restricted, usage={external}) ordered_choice_lister.define_slot_access( :left_list, ## ## This is the list of objects available to be selected. ## :readable) $ _pragma(classify_level=restricted, usage={external}) ordered_choice_lister.define_slot_access( :right_list, ## ## This is the list of selected objects. ## :readable) $ _pragma(classify_level=restricted, topic={editors},usage={external, subclass}) ordered_choice_lister.define_shared_constant(:minimum_width, ## ## This is the default widths of the choice lister list views ## 30,_false) $ _pragma(classify_level=restricted, topic={editors},usage={internal}) ordered_choice_lister.define_shared_constant(:width_sample_size, ## ## This is used to work out how wide the list has to be. The ## choice lister loops over the elements in the list and asks ## the first .width_sample_size how wide their texts are going ## to be. 10,_false) $ #********************************************************************** # Public methods #********************************************************************** _pragma(classify_level=basic, usage={external},topic={editors}) _method ordered_choice_lister.new(a_list, a_model, an_action, _optional a_string_selector, a_list_annotation) ## ## The arguments are ## ## A_LIST :- this should be an indexed collection ## ## A_MODEL :- this is the object to which information on ## selections will be returned ## ## AN_ACTION :- this is the call back method for selection ## which will be sent to the model. The callback message is ## sent with the list of selected objects. ## ## If required, this argument can be preceded by others, ## specified by setting AN_ACTION to a simple vector of the form: ## {,,,...}. ## ## A_STRING_SELECTOR :- this is the method which will be sent to ## the elements in a_lst in order for them to display ## themselved in the list view. By default this is set to ## :write_string ## ## A_LIST_ANNOTATION : Message which is put above the list to give ## additional information as to what the list is showing. >> _clone.init(a_list, a_model, an_action, a_string_selector, a_list_annotation) _endmethod _pragma(classify_level=restricted, topic={editors},usage={internal}) _method ordered_choice_lister.activate_in(a_frame) ## ## This creates the menu items in the frame A_FRAME ## _self.title << "Ordered Choice" .items << hash_table.new() p << panel.new(a_frame) # If we have annotation then put it in above the list _if (annotation << .list_annotation) _isnt _unset _then label_item.new(p, annotation) p.start_row() _endif button_item.new(p,"OK", _self, :|apply()|) button_item.new(p,"Reset", _self, :|reset()|) button_item.new(p,"Quit", _self, :|quit()|) width << _self.determine_list_width() + 5 # Left list p2 << panel.new(a_frame) label_item.new(p2, "Available Items") p2.start_row() .items[:left_list] << list_view.new(_self, p2, :|left_list|, _unset, .string_selector, 10, width, :many) # Arrow buttons p3 << panel.new(a_frame) p3.set_right_of(p2) p3.set_below(p) p3.start_row() label_item.new(p3,"") p3.start_row() button_item.new(p3," >> ", _self, :|add()|, :balloon_help_text, "Move selected items to selection list" ) p3.start_row() button_item.new(p3, " << ", _self, :|remove()|, :balloon_help_text, "Move selected items out of selection list" ) # Right list p4 << panel.new(a_frame) p4.set_right_of(p3) p4.set_below(p) label_item.new(p4, "Selected Items") p4.start_row() .items[:right_list] << list_view.new(_self, p4, :|right_list|, _unset, .string_selector, 10, width, :many) _endmethod $ _pragma(classify_level=restricted, topic={editors},usage={external, internal}) _method ordered_choice_lister.apply() ## ## This sends the current selection back to the model using the ## action specified earlier. ## .action.send_to(.model, .right_list) _self.quit() _endmethod $ _pragma(classify_level=restricted, topic={editors},usage={external, internal}) _method ordered_choice_lister.reset() ## ## Resets lists to original state. ## .left_list << .orig_list .right_list << {} .items[:left_list].update_list(.left_list, _unset) .items[:right_list].update_list(.right_list, _unset) _endmethod $ _pragma(classify_level=restricted, topic={editors},usage={external, internal}) _method ordered_choice_lister.add() ## ## Moves selected items from Available Items list to Selected Items ## _self.move_items(:add) _endmethod $ _pragma(classify_level=restricted, topic={editors},usage={external, internal}) _method ordered_choice_lister.remove() ## ## Moves selected items from Selected Items list to Available Items ## _self.move_items(:remove) _endmethod $ _pragma(classify_level=basic, topic={editors},usage={external, internal}) _method ordered_choice_lister.set_list(a_list) ## ## Resets the object list to A_LIST. ## .orig_list << a_list _self.reset() _endmethod $ _pragma(classify_level=basic, topic={editors},usage={external, internal}) _method ordered_choice_lister.set_selection(an_index) ## ## Selects objects according to AN_INDEX, which is a collection of ## index numbers (must respond to fast_elements() and includes?). ## This can be called before activate() ## olist << .orig_list llist << rope.new() rlist << rope.new() # Populate rlist _for i _over an_index.fast_elements() _loop rlist.add(olist[i]) _endloop # Populate llist _for i _over range(1, olist.size) _loop _if ~ an_index.includes?(i) _then llist.add(olist[i]) _endif _endloop .left_list << llist .right_list << rlist _if .items _is _unset _then _return _endif .items[:left_list].update_list(.left_list, _unset) .items[:right_list].update_list(.right_list, _unset) _endmethod $ _pragma(classify_level=basic, topic={editors},usage={external, internal}) _method ordered_choice_lister.select_all() ## ## Puts all objects into .right_list ## This can be called before activate() ## .left_list << {} .right_list << .orig_list _if .items _is _unset _then _return _endif .items[:left_list].update_list(.left_list, _unset) .items[:right_list].update_list(.right_list, _unset) _endmethod $ #********************************************************************** # Private methods #********************************************************************** _pragma(classify_level=restricted, topic={editors},usage={external}) _private _method ordered_choice_lister.init(a_list, a_model, an_action, _optional a_string_selector, a_list_annotation) .model << a_model .action << an_action .string_selector << a_string_selector.default(:write_string) .list_annotation << a_list_annotation .left_list << .orig_list << a_list .right_list << {} >> _super.init() _endmethod $ _pragma(classify_level=restricted, topic={editors},usage={external}) _private _method ordered_choice_lister.determine_list_width() w << _self.minimum_width n << _self.width_sample_size _for i,s _over .left_list.fast_keys_and_elements() _loop _if i > n _then _leave _endif w << w.max(.string_selector.send_to(s).size) _endloop >> w _endmethod $ _pragma(classify_level=restricted, topic={editors},usage={external}) _private _method ordered_choice_lister.move_items(mode) _if mode _is :add _then from_item << .items[:left_list] from_list << .left_list to_item << .items[:right_list] to_list << rope.new_from(.right_list) _else from_item << .items[:right_list] from_list << .right_list to_item << .items[:left_list] to_list << rope.new_from(.left_list) _endif add_list << rope.new() remainder_list << rope.new() _for i _over range(1,from_list.size) _loop _if from_item.current_index.includes?(i) _then to_list.add(from_list[i]) _else remainder_list.add(from_list[i]) _endif _endloop _if mode _is :add _then .left_list << remainder_list .right_list << to_list _else .left_list << to_list .right_list << remainder_list _endif .items[:left_list].update_list(.left_list, _unset) .items[:right_list].update_list(.right_list, _unset) _endmethod $