######################################################################## #### #### Title: cbfreq.magik #### Author: Mark Cederholm #### Last Revised: 18-Oct-2002 #### #### Notes: #### #### Generate a frequency table from collection_browser contents, #### sending tab-delimited output to a document_previewer_menu, #### suitable for export to other applications. #### #### Requires the sort_menu class. #### ######################################################################## #********************************************************************** # Initialisation #********************************************************************** _block # Add messages _local m << message_handler.new(:browser) m.create_message_non_ds(:frequency_tab, :en_gb, "Frequency Table...") m.create_message_non_ds(:ft!no_records, :en_gb, "No records to process.") m.create_message_non_ds(:ft!no_fields, :en_gb, "No sortable fields.") m.create_message_non_ds(:ft!progress, :en_gb, "Processing... #1") m.create_message_non_ds(:ft!max_recs, :en_gb, "Maximum number of #1 entries exceeded.") # Add method to extra options menu collection_browser.extra_options.add({:frequency_tab, :|frequency_tab()|, _false}) _endblock $ #********************************************************************** # Public methods #********************************************************************** _pragma(classify_level=basic, topic={query,browser}, usage={external}) _method collection_browser.frequency_tab() ## Generates a frequency table from current result, writing results ## to a tab delimited text file. Launches a dialog pick sort and ## summary fields, then a dialog to select the output file. # Check if valid set b << .browser_engine q << b.current_set _if q _is _unset _orif q.n_objects = 0 _then _self.message_alert(:ft!no_records) _return _endif # Create field list t << b.current_table flist << rope.new() _for f _over t.visible_fields.fast_elements() _loop _if f.is_physical? _or f.is_derived? _then tp << f.type _if tp _is _unset _orif tp.is_string? _orif ~ tp.is_vector? _then flist.add(f) _endif _endif _endloop _if flist.size = 0 _then _self.message_alert(:ft!no_fields) _return _endif # Launch sort menu s << sort_menu.new(flist, _self, :|ft!run_thread()|, _true) s.activate() _endmethod $ _pragma(classify_level=basic, topic={query,browser}, usage={external}) _method collection_browser.ft!run_thread(sortlist, sumlist) _self.run_engine(_thisthread.background_priority, :|ft!do_it()|, sortlist, sumlist) _endmethod $ _pragma(classify_level=basic, topic={query,browser}, usage={external}) _method collection_browser.ft!do_it(sortlist, sumlist) _self.busy? << _true _protect # Generate frequency list slist << _self.ft!generate_ftab(sortlist, sumlist) _if slist _isnt _unset _then # Generate output file _self.ft!generate_report(sortlist, sumlist, slist) _endif _protection _self.busy? << _false _endprotect _endmethod $ #********************************************************************** # Private methods #********************************************************************** _pragma(classify_level=basic, topic={query,browser}, usage={external}) _private _method collection_browser.ft!generate_ftab(sortlist, sumlist) # Set up read stream for table b << .browser_engine q << b.current_set _local t << b.current_table test_proc << _proc(r) _import t >> (r.source_collection _is t) _endproc pred << predicate.using(test_proc) rset << q.record_read_stream(pred) # Generate frequency list ftab << hash_table.new() max << !maximum_collection_size! recnum << 0 stat << .item_hash[:status_label] _loop r << rset.get() _if r _is _unset _then _leave _endif recnum +<< 1 _if recnum _mod 100 = 0 _then msg << _self.message(:ft!progress, "Processing... #1", recnum.write_string) stat.label << msg _endif # Build key based on sort field values keys << _unset _for f _over sortlist.fast_elements() _loop val << r.perform(f[1].name).write_string _if keys _is _unset _then keys << val _else keys +<< "$" + val _endif _endloop key << keys.as_symbol() # Add or update entry _if (entry << ftab[key]) _is _unset _then # Check for overflow _if ftab.size = max _then _self.message_alert(:ft!max_recs, max.write_string) _return _unset _endif ivlist << rope.new() _for f _over sortlist.fast_elements() _loop val << r.perform(f[1].name) ivlist.add(val) _endloop isumlist << rope.new() _for f _over sumlist.fast_elements() _loop val << r.perform(f.name).default(0) isumlist.add(val) _endloop entry << {ivlist, 1, isumlist} _else ivlist << entry[1] icount << entry[2] + 1 isumlist << entry[3] i << 0 _for f _over sumlist.fast_elements() _loop i +<< 1 val << r.perform(f.name).default(0) isumlist[i] +<< val _endloop entry << {ivlist, icount, isumlist} _endif ftab[key] << entry _endloop # Create sorted collection sortproc << _proc(arg1,arg2) _import sortlist vlist1 << arg1[1] vlist2 << arg2[1] i << 0 _for e _over sortlist.fast_elements() _loop i +<< 1 dir << e[2] val1 << vlist1[i] val2 << vlist2[i] _if val1 _is _unset _and val2 _is _unset _then _continue _elif val1 _is _unset _then _return (dir _is :ascending) _elif val2 _is _unset _then _return (dir _isnt :ascending) _elif val1 = val2 _then _continue _endif _if dir _is :ascending _then _return (val1 < val2) _else _return (val1 > val2) _endif _endloop >> _maybe _endproc slist << sorted_collection.new(ftab.size, sortproc) slist.add_all(ftab) >> slist _endmethod _pragma(classify_level=basic, topic={query,browser}, usage={external}) _private _method collection_browser.ft!generate_report(sortlist, sumlist, slist) d << document.new() # Write header tab << character.tab s << internal_text_output_stream.new() s.write("count") _for f _over sortlist.fast_elements() _loop val << f[1].name.as_charvec() s.write(tab, val) _endloop _for f _over sumlist.fast_elements() _loop val << "sum_" + f.name.as_charvec() s.write(tab, val) _endloop d.add_line(s.string) # Write records _for e _over slist.fast_elements() _loop ivlist << e[1] icount << e[2] isumlist << e[3] s << internal_text_output_stream.new() s.write(icount) _for v _over ivlist.fast_elements() _loop s.write(tab, v.default("")) _endloop _for sum _over isumlist.fast_elements() _loop s.write(tab, sum) _endloop d.add_line(s.string) _endloop dv << document_previewer_menu.new_with_properties(:document, d) dv.activate() _endmethod $