📄 object.class
字号:
/* object
Base class for all objects
*/
*! version 1.0.1 02jul2003
version 8
class {
class:
class dbstyle dbstyle
}
/* -------------------------------------------------------------------------*/
/* Returns the name of the class, instance, or dynamic attribute at the
specified index of the requested (classmv, instancemv, or dynamicmv) array.
Usage: attribname array_name index
where: array_name is "classmv", "instancemv", or "dynamicmv"
*/
program define attribname
capture _cls nameoflocal .`1'[`2']
class exit `"`r(name)'"'
end
/* -------------------------------------------------------------------------*/
/* Pops the last command off the command log.
Usage: .poplog
*/
program define poplog
.popifendsin poplog
.__LOG.Arrpop
end
/* -------------------------------------------------------------------------*/
/* Pops the last command off the command log if the command terminates in
<str>. Note <str> may not contain ".", or "]", or " ".
Usage: .popifendsin str
*/
program define popifendsin
args str
local lastcmd `.__LOG[`.__LOG.arrnels']'
gettoken tok lastcmd : lastcmd , parse(".] ")
while `"`lastcmd'"' != `""' {
gettoken tok lastcmd : lastcmd , parse(".] ")
}
if `"`tok'"' == `"`str'"' {
.__LOG.Arrpop
}
end
/* -------------------------------------------------------------------------*/
/* Pops the last command if it contains <str>
Usage: .popifcontains str
*/
program define popifcontains
args str
local lastcmd `.__LOG[`.__LOG.arrnels']'
local str : subinstr local lastcmd `"`str'"' `"`str'"', count(local ct)
if `ct' {
.__LOG.Arrpop
}
end
/* -------------------------------------------------------------------------*/
/* Saves all objects of the specified class that are attributes of the
specified object or any object it contains recursively.
Builds a Map of the keys of the saved objects.
*/
program define saveall
args class save
// recurse on all attribs
foreach attrib_arr in instancemv dynamicmv {
if 0`.`attrib_arr'.arrnels' {
_saveall_arr `attrib_arr' `class' `save'
}
}
if ! `.isofclass `class'' { // not saving these
exit
}
if "`.__Map.`.uname'.isa'" != "" { // already saved
exit
}
.__Map.Declare `.uname' = .ref // maintain map
if `save' {
if "`._scheme.isa'" != "" {
local scm <UseScheme> `._scheme.uname'
}
file write $T_loghndl ///
"<BeginItem> `.classname' `.uname' `scm'" _n
if !`.isofclass serset' | 0$T_savesers {
.savetofile $T_loghndl // object's own save
}
file write $T_loghndl "<EndItem>" _n
}
end
program define _saveall_arr
args array class save
forvalues i = 1/0`.`array'.arrnels' {
local attrib `array'[`i']
if "`.`attrib'.isa'" == "class" {
if `.`attrib'.isofclass cell' | /*
*/ "`.`attrib'.classname'" == "serset" | /*
*/ `.`attrib'.isofclass scheme' | /*
*/ `.`attrib'.isofclass container' {
.`attrib'.saveall `class' `save'
}
}
else if "`.`attrib'.isa'" == "array" {
_saveall_arr `attrib' `class' `save'
}
}
end
/* -------------------------------------------------------------------------*/
/* Default program for an object to save itself to disk.
If the object has a __LOG array, then that log is saved, regardless
<EndItem> is spewed.
*/
program define savetofile
args filehndl
if "`.Local.__LOG.isa'" == "array" {
forvalues i = 1/0`.__LOG.arrnels' {
file classwrite `filehndl' __LOG[`i']
file write `filehndl' _n
}
}
end
/* -------------------------------------------------------------------------*/
/* Default program to run a log for an item from a file. Each line
tends to be,
.<memberpgm or memberattrib>....
Often the first few lines of the object's log are processed by the object,
then runfromfile is called to run the remaining lines in the class context.
Processes log until an <EndItem> is encountered.
*/
program define runfromfile
args loghndl
local push 1
file read `loghndl' cmd
gettoken tok : cmd
while "`tok'" != "<EndItem>" & r(eof) == 0 {
if "`tok'" == "<BeginCmd>" { /* stop push */
local push 0
}
else if "`tok'" == "<EndCmd>" { /* restart push */
local push 1
}
else {
if "`tok'" == "__NOLOG__" {
gettoken tok cmd : cmd
local push2 0
}
else local push2 1
if 0$T_nostyles {
if ! 0`._is_scheme_edit `cmd'' {
`cmd'
if `push' & `push2' {
gettoken target : cmd , parse(" =")
if substr(`"`target'"', 1, 9) == ".sersets[" {
// must get new serset key
.__LOG.Arrpush `target' = ///
.__Map.``target'.uname'.ref
}
else { // Standard "push"
.__LOG.Arrpush `macval(cmd)'
}
}
}
}
else {
`cmd'
if `push' & `push2' {
gettoken target : cmd , parse(" =")
if substr(`"`target'"', 1, 9) == ".sersets[" {
// must get new serset key
.__LOG.Arrpush `target' = ///
.__Map.``target'.uname'.ref
}
else { // Standard "push"
.__LOG.Arrpush `macval(cmd)'
}
}
}
}
file read `loghndl' cmd
gettoken tok : cmd
}
end
/* -------------------------------------------------------------------------*/
/* Examines a cmd and returns 1 if it is a scheme edit and 0 otherwise.
*/
program define _is_scheme_edit
local unused : subinstr local 0 ".decl_style" "", count(local ct1)
local unused : subinstr local 0 ".style_edit" "", count(local ct2)
local unused : subinstr local 0 ".editstyle" "" , count(local ct3)
// all editstyles ?
class exit = `ct1' | `ct2' | `ct3'
end
/* -------------------------------------------------------------------------*/
/* Types the log for the object to the screen.
Usage: .showlog [ , lines(#) ]
*/
program define showlog
if "`.__LOG.isa'" != "array" {
exit
}
syntax [, Lines(integer -1) ]
.popifcontains .showlog
if `lines' == -1 {
local lines = `.__LOG.arrnels'
}
forvalues i = 1/`lines' {
di `"`.__LOG[`i']'"'
}
end
/* -------------------------------------------------------------------------*/
/* Puts up a dialog box that allows the attributes of a class to be edited.
!? Passing name is a real kludge, so that we can have a fullname to post
to the log when an attribute is edited, much better if we had an
internal way of tracking this, but the first attempt was VERY
inefficient.
*/
program define dialog_box
.popifcontains .dialog_box
syntax , Name(string) [ALL Classmv Instancemv Dynamicmv Redraw Apply ]
if "`all'`classmv'`instancemv'`dynamicmv'" == "" { /* set defaults */
local instancemv instancemv
local dynamicmv dynamicmv
}
global T_Name `name' /* just easier */
global T_SubNm `._restname'
global T_TopNm `._topname $T_Name'
global T_is_style 0 /* is this a style */
if 0`.isofclass style' {
if ! 0`.hasstyles' {
._populate_stylenames
}
global T_is_style = 0`.hasstyles'
}
local showopts `all' `classmv' `instancemv' `dynamicmv' `apply'
global T_opts `showopts' /* for apply */
/* count attributes */
local tnels 0
foreach opt in classmv instancemv dynamicmv {
if "`all'``opt''" != "" {
local tnels = `tnels' + 0`.`opt'.arrnels'
}
}
if $T_is_style {
local tnels = `tnels' + 1
}
if `tnels' > 400 {
di as error "class has too many attributes for a dialog box"
exit 198
}
/* set up for redraws
* and applies */
if "`redraw'" != "" {
if `.isofclass grid' | `.isofclass graph_g' {
global T_drawobj `.objkey'
/* .implements member_pgm_name would be nice */
}
else {
local apply
di in green "note: object is not a graph, ignoring " /*
*/ "redraw option"
}
}
if "`apply'" != "" {
global T_curobj `.objkey'
}
/* place attribute controls */
global T_percol = 1 + int( (`tnels'-1) / /*
*/ (1 + int((`tnels'-1) / `.dbstyle.ctrls_per_col')) )
local x `.dbstyle.xspace'
local y 0
local ymax 0
local offset 0
if $T_is_style {
._place_controls_from x y ymax : ownstyle `x' `y' `ymax' `offset'
local offset = `offset' + 1
}
if "`all'`classmv'" != "" {
._place_controls_from x y ymax : classmv `x' `y' `ymax' `offset'
local offset = `offset' + 0`.classmv.arrnels'
}
if "`all'`instancemv'" != "" {
._place_controls_from x y ymax : instancemv `x' `y' `ymax' `offset'
local offset = `offset' + 0`.instancemv.arrnels'
}
if "`all'`dynamicmv'" != "" {
._place_controls_from x y ymax : dynamicmv `x' `y' `ymax' `offset'
local offset = `offset' + 0`.dynamicmv.arrnels'
}
global T_numctrls `offset'
/* OK, Cancel buttons */
._place_ok_cancel ymax : `.dbstyle.xspace' `ymax' "`apply'"
local ysz = `ymax' + `.dbstyle.ysize' + 2 * `.dbstyle.yspace' + 8
local xsz = `x' + `.dbstyle.ctrlsize' + `.dbstyle.edctrlsz' + /*
*/ `.dbstyle.txtsize' + 2*`.dbstyle.xgap' + `.dbstyle.xspace'
/* put up the dialog box */
capture noisily window dialog "`name'" . . `xsz' `ysz'
local rc = _rc
/* --------------- process the results -------------------------- */
global T_changed 0
tempname self // just in case edits
.`self' = .ref // delete ourself
if `rc' == 3098 { /* cancelled */
/* possibly reset and redraw */
._post_all , `showopts' reset
if "$T_drawobj" != "" & $T_changed {
.${T_drawobj}.drawgraph
global T_changed 0
}
._style_cleanup
exit
}
._post_all , `showopts' /* post any changes to attributes */
if "$T_drawobj" != "" & $T_changed { /* redraw if changed */
.${T_drawobj}.drawgraph
global T_changed 0
}
/* run a sub-view dialog box if
* requested */
local xpnd = `rc'-3000-$T_is_style
if `xpnd' == 0 & $T_is_style {
._copy_style_db
}
if `xpnd' < 1 {
exit
}
local nels 0
foreach opt in classmv instancemv dynamicmv {
if "`all'``opt''" != "" & "`.`opt'.arrnels'" != "" {
if `xpnd' <= `.`opt'.arrnels' {
_cls nameoflocal `opt'[`xpnd']
._run_view "`opt'[`xpnd']" , `showopts' /*
*/ name(`name'.`r(name)')
/* rerun self */
.dialog_box, `showopts' name(`name')
continue, break
}
local xpnd = `xpnd' - `.`opt'.arrnels'
}
}
._style_cleanup
end
program define _place_controls_from
args xmac ymac ymaxmac colon array x y ymax offset
local ctrlsize `.dbstyle.ctrlsize'
local edsize `.dbstyle.edctrlsz'
local txtsize `.dbstyle.txtsize'
local ysize `.dbstyle.ysize'
local yspace `.dbstyle.yspace'
local ycombosz = `.dbstyle.ysize' * `.dbstyle.combo_lines'
/* put out edit controls for all of
* the attributes */ local x0 = `x'
local xctl = `x0' + `edsize' + `.dbstyle.xgap'
local xtxt = `xctl' + `ctrlsize' + `.dbstyle.xgap'
local xfullsz = `edsize' + `ctrlsize' + `txtsize' + 2*`.dbstyle.xgap'
if "`array'" == "ownstyle" & 0`.hasstyles' {
local j = 1 + 0`offset'
if `j' > 1 & mod((`j'-1), $T_percol) == 0 {
/* shift a column */
local x0 = `x0' + `xfullsz' + `.dbstyle.xspace'
local xctl = `x0' + `edsize' + `.dbstyle.xgap'
local xtxt = `xctl' + `ctrlsize' + `.dbstyle.xgap'
local y = 0
}
local y = `y' + `ysize' + `yspace'
local ymax = max(`y', `ymax')
global T_txt`j' `.classname'
/* combo and label */
window control static T_txt`j' `xctl' /*
*/ `y' `ctrlsize' `ysize' right
global T_codes`j' `.Global.$T_Name.stylelist'
global T_v`j' `.Global.$T_Name.stylename'
global T_hv`j' ${T_v`j'}
window control scombo T_codes`j' `xtxt' `y' /*
*/ `=`ctrlsize'-8' `ycombosz' T_v`j'
/* copy button */
local rc = 3000 + `j'
global T_act`j' exit `rc'
window control button "copy" `x0' `y' `edsize' `ysize' T_act`j'
c_local `xmac' `x0'
c_local `ymac' `y'
c_local `ymaxmac' `ymax'
exit /* EXIT */
}
if "`.`array'.isa'" != "array" {
exit
}
forvalues i = 1/`.`array'.arrnels' {
local j = `i' + 0`offset'
if `j' > 1 & mod((`j'-1), $T_percol) == 0 {
/* shift a column */
local x0 = `x0' + `xfullsz' + `.dbstyle.xspace'
local xctl = `x0' + `edsize' + `.dbstyle.xgap'
local xtxt = `xctl' + `ctrlsize' + `.dbstyle.xgap'
local y = 0
}
local y = `y' + `ysize' + `yspace'
local ymax = max(`y', `ymax')
local attrib `array'[`i']
capture _cls nameoflocal `array'[`i']
local name `r(name)'
if "`name'" == "" {
local name `.`attrib'.classname'
if "`name'" == "" {
local name `j'
}
}
global T_txt`j' "`name'"
if "`.`attrib'.isa'" == "string" {
window control static T_txt`j' `xtxt' `y' /*
*/ `txtsize' `ysize'
global T_v`j' `.`array'[`i']'
global T_hv`j' ${T_v`j'}
window control edit `xctl' `y' `ctrlsize' `ysize' T_v`j'
continue
}
if "`.`attrib'.isa'" == "double" {
window control static T_txt`j' `xtxt' `y' /*
*/ `txtsize' `ysize'
global T_v`j' `.`array'[`i']'
global T_hv`j' ${T_v`j'}
window control edit `xctl' `y' `ctrlsize' `ysize' T_v`j'
continue
}
if "`.`attrib'.isa'" == "class" {
if `.`attrib'.isofclass code' {
window control static T_txt`j' `xtxt' `y' /*
*/ `txtsize' `ysize'
global T_codes`j' `.`attrib'.namelist'
global T_v`j' `.`attrib'.setting'
global T_hv`j' ${T_v`j'}
window control scombo T_codes`j' `xctl' `y' /*
*/ `ctrlsize' `ycombosz' T_v`j'
continue
}
/* merge above ? */
if `.`attrib'.isofclass style' & 0`.`attrib'.hasstyles'{
/* combo and label */
window control static T_txt`j' `xtxt' `y' /*
*/ `txtsize' `ysize' /*same*/
global T_codes`j' `.`attrib'.stylelist'
global T_v`j' `.`attrib'.stylename'
global T_hv`j' ${T_v`j'}
window control scombo T_codes`j' `xctl' `y' /*
*/ `ctrlsize' `ycombosz' T_v`j'
/* edit button */
local rc = 3000 + `j'
global T_act`j' exit `rc'
window control button "edit" `x0' `y' /*
*/ `edsize' `ysize' T_act`j'
continue
}
local rc = 3000 + `j'
global T_act`j' exit `rc'
window control button "`name'" `x0' `y' /*
*/ `xfullsz' `ysize' T_act`j'
continue
/* !? might add boxes for small styles */
}
if "`.`attrib'.isa'" == "array" {
local rc = 3000 + `j'
global T_act`j' exit `rc'
window control button "`name' (array)" `x0' `y' /*
*/ `xfullsz' `ysize' T_act`j'
}
/* would be nice to have booleans and check boxes */
/* should disallow things that are not inherited from object */
}
c_local `xmac' `x0'
c_local `ymac' `y'
c_local `ymaxmac' `ymax'
end
program define _place_ok_cancel
args ymac colon x y apply
local y = `y' + `.dbstyle.ysize' + 2 * `.dbstyle.yspace'
global T_cancel "exit 3098"
global T_ok "exit 3099"
window control button "OK" `x' `y' 30 `.dbstyle.ysize' T_ok
local sx = `x' + 40
window control button "Cancel" `sx' `y' 30 `.dbstyle.ysize' T_cancel
if "`apply'" == "apply" {
local sx = `sx' + 40
global T_apply ".${T_curobj}._db_apply"
window control button "Apply" `sx' `y' 30 /*
*/ `.dbstyle.ysize' T_apply
}
c_local `ymac' `y'
end
program define _post_all
syntax [, All Classmv Instancemv Dynamicmv Redraw Apply REset ]
/* post any changes to attributes */
local log $T_TopNm.__LOG
if ! `._set_changed' {
exit
}
if $T_is_style {
._post_style
if ! 0$T_changed_p1 {
exit
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -