######################################################################## #### #### Title: sort_menu.magik #### Author: Mark Cederholm #### Last Revised: 13-Jun-2002 #### #### Notes: #### #### Sort of a cross between report_default_fields_menu and #### report_sorter_menu, this menu allows the user to pick multiple #### sort fields in ascending or descending order, and optionally #### summary fields. #### ######################################################################## #********************************************************************** # Exemplars #********************************************************************** remex(:sort_menu) $ def_slotted_exemplar(:sort_menu, { {:model, _unset}, {:action, _unset}, {:flist, _unset, :readable}, {:summary?, _unset}, {:sortlist, _unset}, {:sumlist, _unset, :readable}, {:items, _unset} }, :model ) $ #********************************************************************** # Public methods #********************************************************************** _method sort_menu.new(a_list, a_model, an_action, _optional do_summary?) ## ## Creates a new sort_menu, which allows the user to pick multiple ## sort fields in ascending or descending order, and optionally ## summary fields. ## ## The arguments are ## ## A_LIST: a list of field descriptors or any object that ## responds to :external_name ## ## 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 two arguments: ## 1) a rope of simple vectors of the form ## {FIELD, DIRECTION} ## where FIELD is a field descriptor ## and DIRECTION is :ascending or :descending ## 2) a rope of summary field descriptors if DO_SUMMARY? is _true ## else _unset ## ## If required, these arguments can be preceded by others, ## specified by setting AN_ACTION to a simple vector of the form: ## {,,,...} ## ## DO_SUMMARY?: default _false, tells menu whether to display ## additional items for selecting summary fields ## >> _clone.init(a_list, a_model, an_action, do_summary?) _endmethod _method sort_menu.activate_in(a_frame) _self.title << "Sort by Field(s)" .items << hash_table.new() p << panel.new(a_frame) label_item.new(p, "Available Fields:") p.start_row() .items[:available] << list_view.new(_self, p, :flist, _unset, :external_name, _unset,_unset,:many) .items[:available].window.resize_x? << _true p.start_row() .items[:direction] << choice_item.new(p, "Direction", {"Ascending","Descending"}, {:ascending,:descending}, :model, _self) p.start_row() button_item.new(p, "Add to Sort Fields", _self, :|add_to_sort_list()|) p.start_row() _if .summary? _then button_item.new(p, "Add to Summary Fields", _self, :|add_to_summary_list()|) p.start_row() _endif label_item.new(p, "Sort Fields:") p.start_row() .items[:sort] << numbered_list_view.new(_self, p, :|sort_field_list()|, _unset, :write_string, _unset,_unset,:many) .items[:sort].window.resize_x? << _true p.start_row() button_item.new(p, "Clear", _self, :|clear_sort_list()|) button_item.new(p, "Delete", _self, :|delete_from_sort_list()|) p.start_row() _if .summary? _then label_item.new(p, "Summary Fields:") p.start_row() .items[:summary] << list_view.new(_self, p, :sumlist, _unset, :external_name, _unset,_unset,:many) .items[:summary].window.resize_x? << _true p.start_row() button_item.new(p, "Clear", _self, :|clear_summary_list()|) button_item.new(p, "Delete", _self,:|delete_from_summary_list()|) p.start_row() _endif button_item.new(p, "Apply", _self, :|do_and_quit()|) button_item.new(p, "Cancel", _self,:|quit()|) _endmethod _method sort_menu.add_to_sort_list() _self.add_to_list(:sort) _endmethod _method sort_menu.add_to_summary_list() _self.add_to_list(:summary) _endmethod _method sort_menu.sort_field_list() r << rope.new() _for e _over .sortlist.fast_elements() _loop s << internal_text_output_stream.new() s.write(e[1].external_name) _if e[2] _is :ascending _then s.write(" (A)") _else s.write(" (D)") _endif r.add(s.string) _endloop >> r _endmethod _method sort_menu.clear_sort_list() .sortlist << rope.new() .items[:sort].update_list(_self.sort_field_list(), _unset) _endmethod _method sort_menu.delete_from_sort_list() _self.delete_from_list(:sort) _endmethod _method sort_menu.clear_summary_list() .sumlist << rope.new() .items[:summary].update_list(.sumlist, _unset) _endmethod _method sort_menu.delete_from_summary_list() _self.delete_from_list(:summary) _endmethod _method sort_menu.do_and_quit() _if .summary? _then s << .sumlist _else s << _unset _endif .action.send_to(.model, .sortlist, s) _self.quit() _endmethod _method sort_menu.set_list(a_list) ## ## Resets available fields list to A_LIST ## .flist << a_list .items[:available].update_list(.flist, _unset) _self.clear_sort_list() _if .summary? _then _self.clear_summary_list() _endif _endmethod _method sort_menu.set_sort_list(a_list) ## ## Sets sort fields list to A_LIST, which is an indexed collection ## of simple vectors of the form: ## {FIELD, DIRECTION} ## where FIELD is a field descriptor ## and DIRECTION is :ascending or :descending ## This may be performed before activate() ## .sortlist << a_list _if .items _isnt _unset _then .items[:sort].update_list(_self.sort_field_list(), _unset) _endif _endmethod _method sort_menu.set_summary_list(a_list) ## ## Sets summary fields list to A_LIST, which is an indexed ## collection of field descriptors. If DO_SUMMARY? was not set to ## _true during init(), this method will do nothing. ## This may be performed before activate() ## _if ~ .summary? _then _return _endif .sumlist << a_list _if .items _isnt _unset _then .items[:summary].update_list(.sumlist, _unset) _endif _endmethod #********************************************************************** # Private methods #********************************************************************** _private _method sort_menu.init(a_list, a_model, an_action, _optional do_summary?) .model << a_model .action << an_action .flist << a_list .sortlist << rope.new() .sumlist << rope.new() .summary? << do_summary?.default(_false) >> _super.init() _endmethod _private _method sort_menu.add_to_list(option) r << rope.new() _for i _over .items[:available].current_index.fast_elements() _loop f << .flist[i] _if option _is :summary _then # Check if numeric field valid? << _false _if (t << f.type) _isnt _unset _andif t.enumerator _is _unset _then p << t.phys_type _if p _is :ds_int _or p _is :ds_uint _or p _is :ds_byte _or p _is :ds_float _or p _is :ds_double _then valid? << _true _endif _endif _if ~ valid? _then msg << f.external_name + " is not a numeric field." _self.show_alert(msg) _continue _endif _endif # Check if already in sort list f << .flist[i] add? << _true _for e _over .sortlist.fast_elements() _loop _if e[1] _is f _then add? << _false _leave _endif _endloop # Check if already in summary list _for e _over .sumlist.fast_elements() _loop _if e _is f _then add? << _false _leave _endif _endloop _if ~ add? _then msg << f.external_name + " is in use." _self.show_alert(msg) _continue _elif option _is :sort _then r.add({f, .items[:direction].value}) _else r.add(f) _endif _endloop _if r.size = 0 _then _return _endif _if option _is :sort _then .sortlist.add_all_last(r) r << _self.sort_field_list() _else .sumlist.add_all_last(r) r << .sumlist _endif .items[option].update_list(r, _unset) _endmethod _private _method sort_menu.delete_from_list(option) lv << .items[option] _if lv.current_index.size = 0 _then _return _endif _if option _is :sort _then list << .sortlist _else list << .sumlist _endif r << rope.new() _for i _over range(1,list.size) _loop _if ~ lv.current_index.includes?(i) _then r.add(list[i]) _endif _endloop _if option _is :sort _then .sortlist << r r << _self.sort_field_list() _else .sumlist << r _endif lv.update_list(r, _unset) _endmethod