use
5.6.0;
our
$VERSION
= 0.01;
use
vars
qw(@EXPORT_OK %FORM %APP
$APP $FORM $DB $NO_MORE_ROWS)
;
$NO_MORE_ROWS
=
"No more rows in the direction you are going."
;
@EXPORT_OK
=
qw(run)
;
%FORM
=
(
TABORDER
=> [
'Buttons'
,
'DBForm'
],
TYPE
=>
''
,
ALTFBASE
=> [
'DBIx::Informix::Perform::Forms'
,
'DBIx::Informix::Perform::Widgets'
],
ALTBASE
=> [
'DBIx::Informix::Perform::Forms'
,
'DBIx::Informix::Perform::Widgets'
],
FOCUSED
=>
'Buttons'
,
WIDGETS
=> {
Buttons
=> {
TYPE
=>
'ButtonSet'
,
BORDER
=> 0,
X
=> 1,
Y
=> 0,
LABELS
=> [
qw(Query Next Prev. Add Update Remove Exit)
],
LENGTH
=> 6,
FOCUSSWITCH
=>
"\t\nmd"
,
OnExit
=> \
&ButtonPush
,
},
},
);
%APP
=
(
FOREGROUND
=>
'white'
,
BACKGROUND
=>
'black'
,
MAINFORM
=> {
Dummy
=>
'DummyDef'
},
STATUSBAR
=> 1,
EXIT
=> 0,
form_name
=>
'Run0'
,
form_names
=> [
'Run0'
],
form_name_indexes
=> {
Run0
=> 0 },
md_mode
=>
'm'
,
resume_command
=>
undef
,
);
sub
run
{
my
$arg
=
shift
;
my
$form
= load(
$arg
);
$DB
= DBIx::Informix::Perform::DButils::open_db(
$form
->{
'db'
});
run_form(
$form
);
}
sub
run_form
{
my
$form
=
shift
;
my
%appdef
=
%APP
;
if
(
defined
(
my
$minsize
=
$form
->{
'screen'
}{
'MINSIZE'
})) {
@appdef
{
'MINX'
,
'MINY'
} =
@$minsize
;
}
my
$instrs
=
$appdef
{
'instrs'
} =
$form
->{
'instrs'
};
my
$masters
=
$instrs
&&
$$instrs
{
'MASTERS'
};
$appdef
{
'MASTERS'
} =
$masters
;
$appdef
{
'BACKGROUND'
} =
$ENV
{
'BGCOLOR'
}
if
$ENV
{
'BGCOLOR'
};
$APP
= new Curses::Application (\
%appdef
)
or
die
"Unable to create application object"
;
my
$mwh
=
$APP
->mwh();
my
(
$maxy
,
$maxx
) =
$APP
->maxyx();
my
$i
= 0;
my
@subformdefs
= curses_formdefs(
$form
,
$maxy
-2,
$maxx
, \
%appdef
);
my
@formnames
;
foreach
my
$sfd
(
@subformdefs
) {
my
%runformdef
=
%FORM
;
my
$defname
=
"RunDef$i"
;
my
$formname
=
"Run$i"
;
@runformdef
{
qw(X Y LINES COLUMNS DERIVED SUBFORMS)
} =
(0, 0,
$maxy
-1,
$maxx
, 1, {
'DBForm'
=>
$sfd
});
push
(
@formnames
,
$formname
);
$APP
->addFormDef(
$defname
, {
%runformdef
});
$APP
->createForm(
$formname
,
$defname
);
$i
++;
}
$APP
->setField(
MAINFORM
=> {
Run0
=>
'RunDef0'
});
$APP
->setField(
form_names
=> [
@formnames
]);
$APP
->setField(
form_name_indexes
=>
+{
map
{(
$formnames
[
$_
],
$_
)} 0..
$#formnames
});
$APP
->draw();
while
(!
$APP
->getField(
'EXIT'
)) {
my
$fname
=
$APP
->getField(
'form_name'
);
local
$FORM
=
$APP
->getForm(
$fname
);
my
$resumecmd
=
$APP
->getField(
'resume_command'
);
if
(
$resumecmd
) {
&$resumecmd
(
$FORM
);
$APP
->setField(
'resume_command'
,
undef
);
}
$APP
->execForm(
$fname
);
}
}
sub
curses_formdefs
{
my
$formspec
=
shift
;
my
$maxy
=
shift
;
my
$maxx
=
shift
;
my
$appdef
=
shift
;
my
@screens
= @{
$formspec
->{
'screens'
}};
my
$attrs
=
$formspec
->{
'attrs'
};
my
$lineoffset
= 0;
my
@formdefs
= ();
my
$i
= 0;
my
$appbg
=
$$appdef
{
'BACKGROUND'
};
my
$deffldbg
=
$ENV
{
'FIELDBGCOLOR'
} ||
'blue'
;
foreach
my
$screen
(
@screens
) {
my
$widgets
=
$$screen
{
'WIDGETS'
};
my
$fields
=
$$screen
{
'FIELDS'
};
my
$subformfields
=
$fields
;
my
$add_taborder
=
[
grep
{ !
$$attrs
{
$_
}[1]{NOENTRY} }
@$subformfields
];
my
$update_taborder
=
[
grep
{ !
$$attrs
{
$_
}[1]{NOUPDATE} }
@$subformfields
];
my
$defaults
=
+{
map
{
my
$d
=
$$attrs
{
$_
}[1]{DEFAULT};
defined
(
$d
) ? (
$_
,
$d
) : (); }
@$subformfields
};
my
%def
= (
X
=> 0,
Y
=> 1,
COLUMNS
=>
$maxx
,
LINES
=>
$maxy
,
DERIVED
=> 1,
ALTFBASE
=>
'DBIx::Informix::Perform::Forms'
,
ALTBASE
=>
'DBIx::Informix::Perform::Widgets'
,
TABORDER
=>
$fields
,
tables
=>
$formspec
->{
'tables'
},
attrs
=>
$attrs
,
fields
=>
$subformfields
,
add_taborder
=>
$add_taborder
,
update_taborder
=>
$update_taborder
,
defaults
=>
$defaults
,
md_mode
=>
'm'
,
editmode
=>
''
,
);
foreach
my
$f
(
@$fields
) {
my
$w
=
$widgets
->{
$f
};
my
(
$cols
,
$fattrs
) = @{
$$attrs
{
$f
}};
$w
->{
'OnExit'
} =
sub
{
&OnFieldExit
(
$f
,
@_
); };
my
$comments
=
$$fattrs
{
'COMMENTS'
};
$w
->{
'OnEnter'
} =
sub
{
$APP
->statusbar(
$comments
); }
if
(
$comments
);
$w
->{
'FOCUSSWITCH'
} =
"\t\n\cp\cw\cc\ck\c["
;
$w
->{
'FOCUSSWITCH_MACROKEYS'
} = [KEY_UP, KEY_DOWN, KEY_DC];
my
$color
=
$fattrs
->{
'COLOR'
} ||
$deffldbg
;
$w
->{
'BACKGROUND'
} =
$color
;
if
(
$color
eq
$appbg
) {
$$widgets
{
"$f.openbracket"
} =
+{
TYPE
=>
'Label'
,
COLUMNS
=> 1,
ROWS
=> 1,
Y
=>
$w
->{
'Y'
},
X
=>
$w
->{
'X'
}-1,
VALUE
=>
"["
};
$$widgets
{
"$f.closebracket"
} =
+{
TYPE
=>
'Label'
,
COLUMNS
=> 1,
ROWS
=> 1,
Y
=>
$w
->{
'Y'
},
X
=>
$w
->{
'X'
} +
$w
->{
'COLUMNS'
},
VALUE
=>
"]"
};
}
$w
->{
'columns'
} =
$cols
;
$w
->{
'attrs'
} =
$fattrs
;
$w
->{
'savevalue'
} =
''
;
}
$def
{
'WIDGETS'
} = {
%$widgets
},
push
(
@formdefs
, {
%def
});
}
return
@formdefs
;
}
sub
load
{
my
$arg
=
shift
;
if
(
length
(
$arg
) < 500) {
if
(
$arg
=~ /\.per$/) {
return
load_per(
$arg
);
}
elsif
(
$arg
=~ /\.pps/) {
return
load_file(
$arg
);
}
else
{
die
"Unknown file extension on '$arg'"
;
}
}
else
{
if
(
ref
(
$arg
) =~ /HASH/) {
return
$arg
;
}
elsif
(
$arg
=~ /^\s
*database
\s/m) {
require
"DBIx/Informix/Perform/DigestPer.pm"
;
return
DBIx::Informix::Perform::DigestPer::digest_string(
$arg
);
}
elsif
(
$arg
=~ /^\
$form
\s*=/) {
return
load_string(
$arg
);
}
die
"Unrecognized string arg."
;
}
}
sub
load_per
{
my
$file
=
shift
;
open
(PER_IN,
"< $file"
)
||
die
"Unable to open '$file' for reading: $!"
;
require
"DBIx/Informix/Perform/DigestPer.pm"
;
my
$digest
= DBIx::Informix::Perform::DigestPer::digest(\
*PER_IN
);
die
"File did not digest to a Perl Perform Spec"
unless
$digest
=~ /\
$form
\s*=/;
return
load_string(
$digest
);
}
sub
load_file
{
my
$file
=
shift
;
load_internal(
sub
{
require
$file
});
}
sub
load_string
{
my
$string
=
shift
;
load_internal(
sub
{
eval
$string
});
}
sub
load_internal
{
my
$sub
=
shift
;
our
$form
;
local
(
$form
);
&$sub
();
return
$form
;
}
%BUTTONSUBS
=
(
query
=> \
&querymode
,
next
=> \
&do_next
,
'prev.'
=> \
&do_prev
,
add
=> \
&addmode
,
update
=> \
&updatemode
,
remove
=> \
&do_remove
,
exit
=> \
&doquit
,
);
sub
ButtonPush
{
my
$form
=
shift
;
my
$key
=
shift
;
if
(
lc
(
$key
) =~ /[md]/) {
do_master_detail(
lc
(
$key
),
$form
);
return
;
}
my
$wid
=
$form
->getWidget(
'Buttons'
);
my
$val
=
$wid
->getField(
'VALUE'
);
my
$labels
=
$wid
->getField(
'LABELS'
);
my
$thislabel
=
lc
(
$$labels
[
$val
]);
my
$btnsub
=
$BUTTONSUBS
{
$thislabel
};
if
(
$btnsub
&&
ref
(
$btnsub
) eq
'CODE'
) {
&$btnsub
(
$form
);
}
else
{
print
STDERR
"No button sub for '$thislabel'\n"
;
$form
->setField(
'DONTSWITCH'
, 1);
}
}
sub
clear_textfields
{
my
$subform
=
shift
;
my
$fields
=
$subform
->getField(
'fields'
);
return
unless
$fields
;
foreach
my
$f
(
@$fields
) {
$subform
->getWidget(
$f
)->setField(
'VALUE'
,
''
);
}
}
sub
setSubform
{
my
$form
=
shift
;
my
$n
=
shift
;
my
$forms
=
$APP
->getField(
'form_names'
);
my
$fname
=
$$forms
[
$n
];
if
(
$fname
) {
$APP
->setField(
'form_name'
,
$fname
);
$form
->setField(
'EXIT'
, 1);
}
}
use
vars
qw($STH @ROWS $ROWNUM $STHDONE
$MASTER_STH @MASTER_ROWS $MASTER_ROWNUM $MASTER_STHDONE)
;
sub
clear_STH
{
if
(
$STH
) {
eval
{
$STH
->finish() };
undef
$STH
;
@ROWS
= ();
$ROWNUM
= -1;
undef
$STHDONE
;
}
}
sub
check_rows_and_advise
{
my
$form
=
shift
;
if
(
$#ROWS
< 0 || !
defined
(
$ROWNUM
)) {
$APP
->statusbar(
"There are no rows in the current list."
);
$form
->setField(
'DONTSWITCH'
, 1);
return
1;
}
return
undef
;
}
sub
querymode
{
my
$form
=
shift
;
if
(
$APP
->getField(
'md_mode'
) ne
'm'
) {
do_master_detail(
'm'
,
$form
);
$APP
->setField(
'resume_command'
, \
&querymode_resume
);
}
my
$subform
=
$form
->getSubform(
'DBForm'
) ||
$form
;
clear_textfields(
$subform
);
my
$to
=
$subform
->getField(
'fields'
);
$subform
->setField(
'TABORDER'
,
$to
);
$subform
->setField(
'FOCUSED'
,
$to
->[0]);
$subform
->setField(
'editmode'
,
'query'
);
$APP
->statusbar(
"Enter fields to query. ESC queries, DEL cancels."
);
}
sub
querymode_resume
{
my
(
$form
) =
@_
;
querymode(
@_
);
$form
->setField(
'FOCUSED'
,
'DBForm'
);
}
sub
do_master_detail
{
my
$m_or_d
=
shift
;
my
$form
=
shift
;
my
$masters
=
$APP
->getField(
'MASTERS'
);
return
(
$form
->setField(
'DONTSWITCH'
, 1) ,
$APP
->statusbar(
'No detail table for this form.'
))
unless
$masters
;
return
undef
if
(
$APP
->getField(
'md_mode'
) eq
$m_or_d
);
my
$subform
=
$form
->getSubform(
'DBForm'
);
$APP
->setField(
'md_mode'
,
$m_or_d
);
my
(
@wheres
,
@vals
);
if
(
$m_or_d
eq
'd'
) {
if
(
@ROWS
&&
$ROWNUM
>= 0 &&
$ROWS
[
$ROWNUM
]) {
$MASTER_STH
=
$STH
;
@MASTER_ROWS
=
@ROWS
;
$MASTER_ROWNUM
=
$ROWNUM
;
$MASTER_STHDONE
=
$STHDONE
;
$STH
= {};
my
$mrow
=
$MASTER_ROWS
[
$MASTER_ROWNUM
];
my
$mtable
=
$masters
->[0][0];
my
$dtable
=
$masters
->[0][1];
my
$attrs
=
$subform
->getField(
'attrs'
);
my
@keys
=
grep
{
scalar
@{
$$attrs
{
$_
}->[0]} > 1 }
keys
%$attrs
;
foreach
my
$k
(
@keys
) {
my
$f
=
$$attrs
{
$k
};
my
(
$mcol
) =
grep
{
$_
->[0] eq
$mtable
} @{
$f
->[0]};
my
(
$dcol
) =
grep
{
$_
->[0] eq
$dtable
} @{
$f
->[0]};
push
(
@wheres
,
"$dcol->[1] = ?"
);
push
(
@vals
,
$mrow
->{
$mcol
->[1]});
}
my
$n
= do_query_internal(
$dtable
, \
@wheres
, \
@vals
);
setSubform(
$form
, 1);
$APP
->setField(
'resume_command'
,
\
&do_next
);
$n
= 0 +
$n
;
my
$p
= (
$n
== 1 ?
''
:
's'
);
$APP
->statusbar(
"Detail: $n row$p found; row 0"
)
if
$n
;
}
else
{
$APP
->statusbar(
"No active query; not switching to detail mode."
);
}
}
else
{
clear_STH();
$STH
=
$MASTER_STH
;
@ROWS
=
@MASTER_ROWS
;
$ROWNUM
=
$MASTER_ROWNUM
;
$STHDONE
=
$MASTER_STHDONE
;
setSubform(
$form
, 0);
display_row_fields(
$form
,
$ROWS
[
$ROWNUM
],
$ROWNUM
);
}
}
sub
do_next
{
my
$form
=
shift
;
my
$switch
=
shift
;
$form
->setField(
'DONTSWITCH'
, 1)
unless
$switch
;
unless
(
$STH
) {
$APP
->statusbar(
"No query is active."
);
return
;
}
my
(
$row
,
$msg
);
if
(!
defined
(
$ROWNUM
) ||
$ROWNUM
>=
$#ROWS
) {
$row
=
$STH
->fetchrow_hashref()
if
!
$STHDONE
;
if
(
$row
) {
push
(
@ROWS
,
$row
);
$ROWNUM
=
$#ROWS
;
}
else
{
$msg
=
$#ROWS
< 0 ?
"No rows found"
:
$NO_MORE_ROWS
;
$APP
->statusbar(
$msg
);
my
$newbtn
=
@ROWS
? 2 : 0;
$form
->getWidget(
'Buttons'
)->setField(
'VALUE'
,
$newbtn
);
$STHDONE
= 1;
if
(
@ROWS
) {
$row
=
$ROWS
[
$ROWNUM
];
}
else
{
my
$subform
=
$form
->getSubform(
'DBForm'
);
clear_textfields(
$subform
);
return
;
}
}
}
else
{
$row
=
$ROWS
[++
$ROWNUM
];
}
display_row_fields(
$form
,
$row
,
$msg
?
undef
:
$ROWNUM
);
}
sub
do_prev
{
my
$form
=
shift
;
my
$display_rownum
=
$ROWNUM
;
$form
->setField(
'DONTSWITCH'
, 1);
if
(
$ROWNUM
<= 0) {
$APP
->statusbar(
$NO_MORE_ROWS
);
undef
$display_rownum
;
my
$newbtn
=
@ROWS
? 1 : 0;
$form
->getWidget(
'Buttons'
)->setField(
'VALUE'
,
$newbtn
);
}
else
{
--
$ROWNUM
;
}
display_row_fields(
$form
,
$ROWS
[
$ROWNUM
],
$display_rownum
);
}
sub
addmode
{
my
$form
=
shift
;
my
$subform
=
$form
->getSubform(
'DBForm'
);
clear_textfields(
$subform
);
my
$to
=
$subform
->getField(
'add_taborder'
);
$subform
->setField(
'TABORDER'
,
$to
);
$subform
->setField(
'FOCUSED'
,
$to
->[0]);
$subform
->setField(
'editmode'
,
'add'
);
my
$defs
=
$subform
->getField(
'defaults'
);
foreach
my
$f
(
keys
%{
$defs
|| {} }) {
my
$v
=
$$defs
{
$f
};
$v
= POSIX::strftime(
"%Y-%m-%d"
,
localtime
())
if
uc
(
$v
) eq
'TODAY'
;
$subform
->getWidget(
$f
)->setField(
'VALUE'
,
$v
);
}
$APP
->statusbar(
"Enter row to add. ESC stores; DEL cancels the add."
);
}
sub
updatemode
{
my
$form
=
shift
;
return
if
check_rows_and_advise(
$form
);
my
$subform
=
$form
->getSubform(
'DBForm'
);
my
$fields
=
$subform
->getField(
'fields'
);
my
$row
=
$ROWS
[
$ROWNUM
];
my
$attrs
=
$subform
->getField(
'attrs'
);
foreach
my
$f
(
@$fields
) {
my
$w
=
$subform
->getWidget(
$f
);
my
$col
=
$attrs
->{
$f
}[0][0][1];
$w
->setField(
'savevalue'
,
$row
->{
$col
});
}
my
$to
=
$subform
->getField(
'update_taborder'
);
$subform
->setField(
'TABORDER'
,
$to
);
$subform
->setField(
'FOCUSED'
,
$to
->[0]);
$subform
->setField(
'editmode'
,
'update'
);
$APP
->statusbar(
"Update the row. ESC stores; DEL cancels the update."
);
}
sub
edit_control
{
my
$field
=
shift
;
my
$subform
=
shift
;
my
$when
=
lc
(
shift
);
my
$instrs
=
$APP
->getField(
'instrs'
);
my
$controls
=
$instrs
->{
'CONTROLS'
};
my
$attrs
=
$subform
->getField(
'attrs'
);
my
(
$fldtblcols
,
$fldattrs
) = @{
$attrs
->{
$field
}};
my
@cols
=
map
{
$_
->[1] }
@$fldtblcols
;
my
$emode
=
$subform
->getField(
'editmode'
);
my
$event
=
"edit$emode"
;
my
@actions
=
map
{
$controls
->{
$_
}{
$event
}{
$when
}}
@cols
;
@actions
=
map
{
$_
?
@$_
: () }
@actions
;
foreach
my
$ac
(
@actions
) {
my
(
$ac
,
$field
,
$opd1
,
$op
,
$opd2
) =
@$ac
;
if
(
$ac
eq
'nextfield'
){
if
(
grep
{
$field
eq
$_
} @{
$subform
->getField(
'TABORDER'
)}) {
$subform
->setField(
'FOCUSED'
,
$field
);
}
}
elsif
(
$ac
eq
'let'
) {
my
$widget
=
$subform
->getWidget(
$field
);
$APP
->statusbar(
"No field '$field' in control block."
),
return
()
unless
$widget
;
$APP
->statusbar(
"Unrecognized operator '$op' in control block."
),
return
()
unless
$op
=~ /^[-+*\/]$/;
my
$val1
= field_value_or_require_quotes(
$opd1
,
$subform
);
my
$val2
= field_value_or_require_quotes(
$opd2
,
$subform
);
my
$result
=
eval
"$val1 $op $val2"
;
if
($@) {
$APP
->statusbar(
"In control block: $@"
);
return
;
}
$widget
->setField(
'VALUE'
,
$result
);
$subform
->setField(
'REDRAW'
, 1);
}
}
}
sub
field_value_or_require_quotes
{
my
$opd
=
shift
;
my
$subform
=
shift
;
my
$w1
=
$subform
->getWidget(
$opd
);
if
(
$w1
) {
my
$val
=
$w1
->getField(
'VALUE'
);
$val
=~ s/\'/\\\'/;
return
"'$val'"
;
}
unless
(
$opd
=~ /^\"(.*)\"$|^(\d+(\.\d_)?)$/) {
$APP
->statusbar(
"Neither field, number nor quoted string: '$opd' in control block"
);
return
"''"
;
}
my
$val
=
defined
($1) ? $1 : $2;
$val
=~ s/\'/\\\'/;
return
"'$val'"
;
}
sub
do_remove
{
my
$form
=
shift
;
return
if
check_rows_and_advise(
$form
);
my
$subform
=
$form
->getSubform(
'DBForm'
);
my
$fields
=
$subform
->getField(
'fields'
);
my
@wheres
= ();
my
@values
= ();
my
$tables
=
$subform
->getField(
'tables'
);
my
(
$table
) =
@$tables
;
my
$row
=
$ROWS
[
$ROWNUM
];
{
foreach
my
$f
(
@$fields
) {
my
$fieldspec
=
$subform
->getField(
'attrs'
)->{
$f
}[0];
my
(
$tbl
,
$col
) =
@$fieldspec
[0,1];
next
if
$tbl
ne
$table
;
my
$v
=
$$row
{
$col
};
push
(
@wheres
,
defined
(
$v
) ?
"$col = ?"
:
"$col is null"
);
push
(
@values
,
$v
)
if
defined
(
$v
);
}
my
$wheres
=
join
' and '
,
@wheres
;
my
$cmd
=
"delete from $table where $wheres"
;
my
$rc
=
$DB
->
do
(
$cmd
, {},
@values
);
if
(!
defined
$rc
) {
$APP
->statusbar(
"Database error: $DBI::errstr"
);
}
else
{
my
$msg
=
"Row removed."
;
splice
(
@ROWS
,
$ROWNUM
, 1);
$ROWNUM
=
$#ROWS
if
$ROWNUM
>
$#ROWS
;
clear_textfields(
$subform
);
}
}
$form
->setField(
'DONTSWITCH'
, 1);
}
sub
doquit
{
my
$form
=
shift
;
$form
->setField(
'EXIT'
, 1);
$APP
->setField(
'EXIT'
, 1);
}
%MODESUBS
=
(
query
=> \
&do_query
,
add
=> \
&do_add
,
update
=> \
&do_update
,
);
sub
OnFieldExit
{
my
(
$field
,
$form
,
$key
) =
@_
;
my
$widget
=
$form
->getWidget(
$field
);
edit_control(
$field
,
$form
,
'after'
);
if
(
$key
eq
"\t"
||
$key
eq
"\n"
||
$key
eq KEY_DOWN) {
$APP
->statusbar(
""
)
if
(
$widget
->getField(
'attrs'
)->{COMMENTS});
return
;
}
my
$dontswitch
= 1;
if
(
$key
eq
"\c["
) {
my
$btns
=
$FORM
->getWidget(
'Buttons'
);
my
$mode
=
lc
((
$btns
->getField(
'LABELS'
))->[
$btns
->getField(
'VALUE'
)]);
my
$sub
=
$MODESUBS
{
$mode
};
if
(
$sub
&&
ref
(
$sub
) eq
'CODE'
) {
$dontswitch
= 0;
&$sub
(
$field
,
$widget
,
$form
);
}
else
{
beep();
}
}
elsif
(
$key
eq
"\cw"
) {
my
$msg
=
$widget
->getField(
'HELPMSG'
);
$APP
->statusbar(
$msg
)
if
(
$msg
);
}
elsif
(
$key
eq
"\cp"
) {
$APP
->statusbar(
"Current-Value-Of-This-Row not working yet"
);
}
elsif
(
$key
eq
"\cc"
) {
clear_textfields(
$form
);
}
elsif
(
$key
eq KEY_DC) {
if
(
$#ROWS
>= 0) {
display_row_fields(
$form
,
$ROWS
[
$ROWNUM
],
$ROWNUM
);
}
else
{
clear_textfields(
$form
);
}
$APP
->statusbar(
""
)
if
(
$widget
->getField(
'attrs'
)->{COMMENTS});
$form
->setField(
'EXIT'
, 1);
}
elsif
(
$key
eq
"\cK"
||
$key
eq KEY_UP ||
$key
eq KEY_STAB) {
my
$taborder
=
$form
->getField(
'TABORDER'
);
my
%taborder
=
map
{ (
$$taborder
[
$_
],
$_
) } (0..
$#$taborder
);
my
$i
=
$taborder
{
$form
->getField(
'FOCUSED'
)};
$i
= (
$i
<= 0) ?
$#$taborder
:
$i
- 1;
$form
->setField(
'FOCUSED'
,
$$taborder
[
$i
]);
$APP
->statusbar(
""
)
if
(
$widget
->getField(
'attrs'
)->{COMMENTS});
$dontswitch
= 0;
}
if
(
$dontswitch
) {
$form
->setField(
'DONTSWITCH'
, 1);
}
}
sub
validate_contents
{
my
$subform
=
shift
;
my
$f
=
shift
;
my
$attrs
=
shift
;
my
$v
=
shift
;
my
$msg
;
$msg
=
"This field requires a value"
if
(
$$attrs
{
'REQUIRED'
} && !
defined
(
$v
)) ;
my
$inc
=
$$attrs
{
'INCLUDE'
};
my
$inchash
=
$$attrs
{
'INCLUDEHASH'
};
$msg
||=
"Field permissible values: $inc"
if
(
$inchash
&& !
$$inchash
{
$v
});
return
1
unless
$msg
;
$APP
->statusbar(
$msg
);
$subform
->setField(
'FOCUSED'
,
$f
);
$subform
->setField(
'DONTSWITCH'
, 1);
return
undef
;
}
sub
do_query
{
my
$field
=
shift
;
my
$widget
=
shift
;
my
$subform
=
shift
;
my
$masters
=
$APP
->getField(
'MASTERS'
);
my
$attrs
=
$subform
->getField(
'attrs'
);
my
@tables
= @{
$subform
->getField(
'tables'
)};
my
(
$table
,
$detail
);
if
(
$masters
) {
my
$mdpair
=
$$masters
[0];
my
$indexes
=
$APP
->getField(
'form_name_indexes'
);
my
$formindex
=
$$indexes
{
$APP
->getField(
'form_name'
)};
my
$mdmode
=
$APP
->getField(
'md_mode'
);
my
$mdindex
=
$mdmode
eq
'm'
? 0 :
$mdmode
eq
'd'
? 1 :
undef
;
die
"Masters exist in instructions but md_mode is '$mdmode'"
unless
defined
(
$mdindex
);
$table
=
$$mdpair
[
$mdindex
];
$detail
=
$mdindex
!= 0;
}
my
@wheres
= ();
my
@vals
= ();
foreach
my
$f
(@{
$subform
->getField(
'fields'
)}) {
my
(
$fldtblcols
,
$fldattrs
) = @{
$attrs
->{
$f
}};
my
@fldtblcols
=
@$fldtblcols
;
next
if
$masters
&&
!
grep
{
$fldtblcols
[
$_
]->[0] eq
$table
} 0..
$#fldtblcols
;
my
(
$tbl
,
$col
) = @{
$fldtblcols
[0]};
if
(!
$masters
&&
$#fldtblcols
> 0) {
my
(
$tbl2
,
$col2
) = @{
$fldtblcols
[1]};
push
(
@wheres
,
"$tbl.$col = $tbl2.$col2"
);
}
my
$val
=
$subform
->getWidget(
$f
)->getField(
'VALUE'
);
next
if
(
$val
eq
''
);
my
$op
=
'='
;
my
$cval
=
$val
;
if
(
$val
=~ /[*%?]$/) {
$cval
=~
tr
/*?/
%_
/;
$op
=
'like'
;
}
if
(
$val
eq
'='
) {
$op
=
'is null'
;
$cval
=
undef
;
}
elsif
(
$val
=~ /^(<<|>>)\s*(.*)$/) {
$APP
->statusbar(
"The $1 operator is not supported yet."
);
}
elsif
(
$val
=~ /^([<>][<=>]?)\s*(.*)$/) {
$op
= $1;
$cval
= $2;
}
elsif
(
$val
=~ /^(.+?):(.+)$/) {
$op
=
"between ? and "
;
push
(
@vals
, $1);
$cval
= $2;
}
elsif
(
$val
=~ /^(.+?)\|(.+)$/) {
$op
=
"= ? or $col = "
;
push
(
@vals
, $1);
$cval
= $2;
}
my
$where
=
"$tbl.$col $op"
. (
defined
(
$cval
) ?
' ?'
:
''
);
push
(
@wheres
,
$where
);
push
(
@vals
,
$cval
)
if
defined
(
$cval
);
}
my
$tables
=
$masters
?
$table
:
join
', '
,
@tables
;
my
$n
= do_query_internal(
$tables
, \
@wheres
, \
@vals
);
$subform
->setField(
'EXIT'
, 1);
unless
(
defined
(
$n
)) {
$APP
->statusbar(
"DB Error on execute: $DBI::errstr"
);
return
;
}
$n
= 0 +
$n
;
do_next(
$FORM
,
'switch'
);
$APP
->statusbar(
"$n row"
. (
$n
== 1 ?
''
:
's'
) .
" found; Row 0"
)
if
$n
> 0;
}
sub
do_query_internal
{
my
$tables
=
shift
;
my
$wheres_ref
=
shift
;
my
$vals_ref
=
shift
;
my
$wheres
=
join
' and '
,
@$wheres_ref
;
my
$query
=
"select * from $tables "
. (
$wheres
?
"where $wheres"
:
''
);
clear_STH();
$STH
=
$DB
->prepare_cached(
$query
);
unless
(
$STH
) {
$APP
->statusbar(
"DB Error on prepare: $DBI::errstr"
);
return
;
}
return
$STH
->execute(
@$vals_ref
);
}
sub
do_add
{
my
$field
=
shift
;
my
$widget
=
shift
;
my
$subform
=
shift
;
my
$fields
=
$subform
->getField(
'fields'
);
my
@cols
= ();
my
@values
= ();
my
$tables
=
$subform
->getField(
'tables'
);
my
(
$table
) =
@$tables
;
my
$row
= {};
{
foreach
my
$f
(
@$fields
) {
my
$fieldattrs
=
$subform
->getField(
'attrs'
)->{
$f
};
my
(
$fieldspecs
,
$attrs
) =
@$fieldattrs
;
next
if
$$attrs
{
'NOENTRY'
};
my
$fieldspec
=
$$fieldspecs
[0];
my
(
$tbl
,
$col
) =
@$fieldspec
[0,1];
next
if
$tbl
ne
$table
;
my
$v
=
$subform
->getWidget(
$f
)->getField(
'VALUE'
);
undef
$v
if
$v
eq
''
;
return
unless
validate_contents(
$subform
,
$f
,
$attrs
,
$v
);
push
(
@cols
,
$col
);
push
(
@values
,
$v
);
$$row
{
$col
} =
$v
;
}
my
$holders
=
join
', '
,
map
{
"?"
}
@cols
;
my
$cols
=
join
', '
,
@cols
;
my
$cmd
=
"insert into $table ($cols) values ($holders)"
;
my
$rc
=
$DB
->
do
(
$cmd
, {},
@values
);
if
(!
defined
$rc
) {
$APP
->statusbar(
"Database error: $DBI::errstr"
);
return
;
}
else
{
$APP
->statusbar(
"Row Added."
);
}
}
$subform
->setField(
'EXIT'
, 1);
clear_STH();
@ROWS
= (
$row
);
$ROWNUM
= 0;
$STH
= {};
$STHDONE
= 1;
}
sub
do_update
{
my
$field
=
shift
;
my
$widget
=
shift
;
my
$subform
=
shift
;
my
$fields
=
$subform
->getField(
'fields'
);
my
%wheres
= ();
my
%upds
= ();
my
$tables
=
$subform
->getField(
'tables'
);
my
(
$table
) =
@$tables
;
my
$row
= {};
my
$attrs
=
$subform
->getField(
'attrs'
);
{
foreach
my
$f
(
@$fields
) {
my
(
$fieldspec
,
$attrs
) = @{
$attrs
->{
$f
}};
my
(
$tbl
,
$col
) = @{
$$fieldspec
[0]};
next
if
$tbl
ne
$table
;
my
$w
=
$subform
->getWidget(
$f
);
my
$v
=
$w
->getField(
'VALUE'
);
undef
$v
if
$v
eq
''
;
return
unless
validate_contents(
$subform
,
$f
,
$attrs
,
$v
);
my
$sv
=
$w
->getField(
'savevalue'
);
$$row
{
$col
} =
$v
;
$upds
{
$col
} =
$v
if
(
$v
ne
$sv
&& !
$$attrs
{
'NOUPDATE'
});
$wheres
{
$col
} =
$sv
;
}
my
@updcols
=
keys
(
%upds
);
my
@updvals
=
map
{
$upds
{
$_
} }
@updcols
;
my
$sets
=
join
(
', '
,
map
{
"$_ = ?"
}
@updcols
);
my
@wherecols
=
keys
(
%wheres
);
my
@wherevals
=
map
{
my
$w
=
$wheres
{
$_
};
defined
(
$w
) ?
(
$w
) : () }
@wherecols
;
my
%updinds
=
map
{ (
$updcols
[
$_
],
$_
) } 0..
$#updcols
;
my
$wheres
=
join
(
' and '
,
map
{
defined
(
$wheres
{
$_
}) ?
"$_ = ?"
:
"$_ is null"
}
@wherecols
);
my
$cmd
=
"update $table set $sets where $wheres"
;
my
$rc
=
$DB
->
do
(
$cmd
, {},
@updvals
,
@wherevals
);
if
(!
defined
$rc
) {
$APP
->statusbar(
"Database error: $DBI::errstr"
);
return
;
}
else
{
$APP
->statusbar((0+
$rc
) .
" rows affected"
);
my
$query
=
"select * from $table where $wheres"
;
grep
{
$ROWS
[
$ROWNUM
]->{
$_
} =
$row
->{
$_
} =
$updvals
[
$updinds
{
$_
}];}
@updcols
;
display_row_fields(
$subform
,
$ROWS
[
$ROWNUM
]);
}
}
$subform
->setField(
'EXIT'
, 1);
}
sub
display_row_fields
{
my
$form
=
shift
;
my
$row
=
shift
;
my
$n
=
shift
;
my
$subform
=
$form
->getSubform(
'DBForm'
) ||
$form
;
my
$fields
=
$subform
->getField(
'fields'
);
my
$attrs
=
$subform
->getField(
'attrs'
);
foreach
my
$f
(
@$fields
) {
my
$attr
=
$attrs
->{
$f
}[0][0];
my
(
$tbl
,
$col
,
$stuff
) =
@$attr
;
$subform
->getWidget(
$f
)->setField(
'VALUE'
,
$row
->{
$col
});
}
$APP
->statusbar(
"Row number $n"
)
if
(
defined
(
$n
));
}