use
subs
qw/menu_struct/
;
Construct Tk::Widget
'ConfigModelListEditor'
;
my
@fbe1
=
qw/-fill both -expand 1/
;
my
@fxe1
=
qw/-fill x -expand 1/
;
my
@fx
=
qw/-fill x /
;
my
$logger
= Log::Log4perl::get_logger(
"Tk::ListEditor"
);
my
(
$up_img
,
$down_img
,
$eraser_img
,
$remove_img
,
$sort_img
);
*icon_path
=
*Config::Model::TkUI::icon_path
;
my
$entry_width
= 20;
sub
ClassInit {
my
(
$cw
,
$args
) =
@_
;
}
sub
Populate {
my
(
$cw
,
$args
) =
@_
;
my
$list
=
$cw
->{list} =
delete
$args
->{-item}
||
die
"ListEditor: no -item, got "
,
keys
%$args
;
delete
$args
->{-path};
my
$cme_font
=
delete
$args
->{-font};
$cw
->{store_cb} =
delete
$args
->{-store_cb}
or
die
__PACKAGE__,
"no -store_cb"
;
unless
(
defined
$up_img
) {
$up_img
=
$cw
->Photo(
-file
=>
$icon_path
.
'up.png'
);
$down_img
=
$cw
->Photo(
-file
=>
$icon_path
.
'down.png'
);
$eraser_img
=
$cw
->Photo(
-file
=>
$icon_path
.
'eraser.png'
);
$remove_img
=
$cw
->Photo(
-file
=>
$icon_path
.
'remove.png'
);
$sort_img
=
$cw
->Photo(
-file
=>
$icon_path
.
'dbgrun.png'
);
}
$cw
->add_header(
Edit
=>
$list
)->
pack
(
@fx
);
my
$balloon
=
$cw
->Balloon(
-state
=>
'balloon'
);
my
$inst
=
$list
->instance;
my
$value_type
=
$list
->get_cargo_info(
'value_type'
);
my
$elt_button_frame
=
$cw
->Frame(
qw/-relief raised -borderwidth 2/
)->
pack
(
@fbe1
);
my
$frame_title
=
$list
->element_name;
$frame_title
.= (
defined
$value_type
and
$value_type
=~ /node/ ) ?
' elements'
:
' list'
;
$elt_button_frame
->Label(
-text
=>
$frame_title
)->
pack
();
my
$tklist
=
$elt_button_frame
->Scrolled(
'Listbox'
,
-selectmode
=>
'single'
,
-scrollbars
=>
'oe'
,
-height
=> 8,
)->
pack
(
@fbe1
);
$balloon
->attach(
$tklist
,
-msg
=>
'select an element and perform an action with one of the buttons below'
);
my
$right_frame
=
$elt_button_frame
->Frame->
pack
(
@fxe1
,
qw/-side right -anchor n/
);
$cw
->ConfigModelNoteEditor(
-object
=>
$list
)->
pack
;
$cw
->add_summary(
$list
)->
pack
(
@fx
);
$cw
->add_description(
$list
)->
pack
(
@fbe1
);
$cw
->add_warning(
$list
,
'edit'
)->
pack
(
@fx
);
$cw
->add_info_button(
$cw
)->
pack
(
@fx
);
my
$mv_rm_frame
=
$right_frame
->Frame->
pack
(
@fx
);
my
$move_up_b
=
$mv_rm_frame
->Button(
-image
=>
$up_img
,
-command
=>
sub
{
$cw
->move_up; },
)->
pack
(
-side
=>
'left'
,
@fxe1
);
$balloon
->attach(
$move_up_b
,
-msg
=>
'Move selected element up the list'
);
my
$move_down_b
=
$mv_rm_frame
->Button(
-image
=>
$down_img
,
-command
=>
sub
{
$cw
->move_down; },
)->
pack
(
-side
=>
'left'
,
@fxe1
);
$balloon
->attach(
$move_down_b
,
-msg
=>
'Move selected element down the list'
);
my
$eraser_b
=
$mv_rm_frame
->Button(
-image
=>
$eraser_img
,
-command
=>
sub
{
$cw
->remove_selection; },
)->
pack
(
-side
=>
'left'
,
@fxe1
);
$balloon
->attach(
$eraser_b
,
-msg
=>
'Remove selected element from the list'
);
my
$rm_all_b
=
$mv_rm_frame
->Button(
-image
=>
$remove_img
,
-command
=>
sub
{
$list
->clear;
$tklist
->
delete
( 0,
'end'
);
$cw
->{store_cb}->();
},
)->
pack
(
-side
=>
'left'
,
@fxe1
);
$balloon
->attach(
$rm_all_b
,
-msg
=>
'Remove all elements from the list'
);
my
$cargo_type
=
$list
->cargo_type;
if
(
$cargo_type
eq
'leaf'
) {
my
$sort_b
=
$mv_rm_frame
->Button(
-image
=>
$sort_img
,
-command
=>
sub
{
$cw
->sort_content } )->
pack
(
-side
=>
'left'
,
@fxe1
);
$balloon
->attach(
$sort_b
,
-msg
=>
'Sort all elements in the list'
);
}
if
(
$cargo_type
eq
'leaf'
and
$value_type
ne
'enum'
and
$value_type
ne
'reference'
) {
my
$set_push_b_entry_frame
=
$right_frame
->Frame(
-borderwidth
=> 2,
-relief
=>
'groove'
)->
pack
(
@fxe1
);
my
$user_value
;
my
$value_entry
=
$set_push_b_entry_frame
->Entry(
-textvariable
=> \
$user_value
,
-width
=>
$entry_width
);
my
$set_push_b_frame
=
$set_push_b_entry_frame
->Frame->
pack
(
@fxe1
);
$cw
->add_set_entry(
$set_push_b_frame
,
$balloon
,
$tklist
, \
$user_value
)->
pack
(
@fxe1
);
$cw
->add_insort_entry(
$set_push_b_frame
,
$balloon
, \
$user_value
)->
pack
(
@fxe1
);
$cw
->add_insert_entry(
$set_push_b_frame
,
$balloon
, \
$user_value
)->
pack
(
@fxe1
);
$cw
->add_set_all_b(
$set_push_b_entry_frame
,
$set_push_b_frame
,
$balloon
, \
$user_value
)
->
pack
(
@fxe1
);
$value_entry
->
pack
(
@fxe1
);
$cw
->add_warning(
$list
,
'edit'
)->
pack
(
@fx
);
}
else
{
my
$elt_name
=
$list
->element_name;
my
$disp
=
"$elt_name ( $cargo_type "
;
$disp
.=
$list
->config_class_name .
' )'
if
$cargo_type
eq
'node'
;
$disp
.=
" $value_type )"
if
defined
$value_type
;
my
$b
=
$right_frame
->Button(
-text
=>
"Push new $disp"
,
-command
=>
sub
{
$cw
->push_entry(
''
); },
)->
pack
(
@fxe1
);
$balloon
->attach(
$b
,
-msg
=>
"add a new $elt_name at the end of the list"
);
}
$cw
->{tklist} =
$tklist
;
$cw
->reset_value;
$cw
->ConfigSpecs(
-font
=> [[
'SELF'
,
'DESCENDANTS'
],
'font'
,
'Font'
,
$cme_font
],);
$cw
->Tk::Frame::Populate(
$args
);
}
sub
reset_value {
my
$cw
=
shift
;
my
$list
=
$cw
->{list};
my
$cargo_type
=
$list
->cargo_type;
$cw
->{tklist}->
delete
( 0,
'end'
);
my
@insert
=
$cargo_type
eq
'leaf'
?
$list
->fetch_all_values(
check
=>
'no'
)
:
$list
->fetch_all_indexes;
$cw
->{tklist}->insert(
end
=>
@insert
);
return
(
$cargo_type
, \
@insert
);
}
sub
add_set_entry {
my
(
$cw
,
$frame
,
$balloon
,
$tklist
,
$user_value_r
) =
@_
;
my
$set_sub
=
sub
{
$cw
->set_entry(
$$user_value_r
); };
my
$set_b
=
$frame
->Button(
-text
=>
"set selected"
,
-command
=>
$set_sub
,
)->
pack
(
-side
=>
'left'
,
@fxe1
);
$balloon
->attach(
$set_b
,
-msg
=>
'enter a value, select an element on the left '
.
'and click the button to replace the selected '
.
'element with this value.'
);
my
$b_sub
=
sub
{
my
$idx
=
$tklist
->curselection;
$$user_value_r
=
$tklist
->get(
$idx
)
if
$idx
;
};
$tklist
->
bind
(
'<<ListboxSelect>>'
,
$b_sub
);
return
$set_b
;
}
sub
add_push_entry {
my
(
$cw
,
$frame
,
$balloon
,
$user_value_r
) =
@_
;
my
$push_sub
=
sub
{
$cw
->push_entry(
$$user_value_r
);
$$user_value_r
=
''
; };
my
$push_b
=
$frame
->Button(
-text
=>
"push item"
,
-command
=>
$push_sub
,
)->
pack
(
-side
=>
'left'
,
@fxe1
);
$balloon
->attach(
$push_b
,
-msg
=>
'enter a value, and click the push button to add '
.
'this value at the end of the list'
);
return
$push_b
;
}
sub
push_entry {
my
$cw
=
shift
;
my
$add
=
shift
;
my
$tklist
=
$cw
->{tklist};
my
$list
=
$cw
->{list};
$logger
->debug(
"push_entry: $add"
);
my
@idx
=
$list
->fetch_all_indexes;
eval
{
$list
->fetch_with_id(
scalar
@idx
) };
if
($@) {
$cw
->CmeDialog(
-title
=>
"List index error"
,
-text
=> $@->as_string,
)->Show;
}
else
{
$cw
->{store_cb}->();
my
@new_idx
=
$list
->fetch_all_indexes;
$logger
->debug(
"new list idx: "
.
join
(
','
,
@new_idx
) );
my
$insert
=
length
(
$add
) ?
$add
:
$#new_idx
;
$tklist
->insert(
'end'
,
$insert
);
}
return
1;
}
sub
add_insert_entry {
my
(
$cw
,
$frame
,
$balloon
,
$user_value_r
) =
@_
;
my
$insert_sub
=
sub
{
$cw
->insert_entry(
$$user_value_r
);
$$user_value_r
=
''
; };
my
$insert_b
=
$frame
->Button(
-text
=>
"insert item"
,
-command
=>
$insert_sub
,
)->
pack
(
-side
=>
'left'
,
@fxe1
);
$balloon
->attach(
$insert_b
,
-msg
=>
'enter a value, and click the insert button to add '
.
'this value before the selected item or at the end of the list (push)'
);
return
$insert_b
;
}
sub
insert_entry {
my
$cw
=
shift
;
my
$add
=
shift
;
my
$tklist
=
$cw
->{tklist};
my
$list
=
$cw
->{list};
my
$idx_ref
=
$tklist
->curselection || [];
my
$idx
=
$idx_ref
->[0];
$logger
->debug(
"insert_entry: $add insert at index "
,
$idx
||
'end'
);
print
(
"insert_entry: $add insert at index "
,
$idx
||
'end'
,
"\n"
);
return
unless
length
(
$add
);
my
$try_sub
=
defined
$idx
?
sub
{
$list
->insert_at(
$idx
,
$add
); } :
sub
{
$list
->
push
(
$add
) };
$cw
->try_and_redraw(
$try_sub
);
}
sub
set_entry {
my
$cw
=
shift
;
my
$data
=
shift
;
my
$tklist
=
$cw
->{tklist};
my
$idx_ref
=
$tklist
->curselection();
return
unless
defined
$idx_ref
;
return
unless
@$idx_ref
;
my
$idx
=
$idx_ref
->[0];
return
unless
$idx
;
$tklist
->
delete
(
$idx
);
$tklist
->insert(
$idx
,
$data
);
$tklist
->selectionSet(
$idx
);
$cw
->{list}->fetch_with_id(
$idx
)->store(
$data
);
$cw
->{store_cb}->();
}
sub
add_insort_entry {
my
(
$cw
,
$frame
,
$balloon
,
$user_value_r
) =
@_
;
my
$insort_sub
=
sub
{
$cw
->insort_entry(
$$user_value_r
);
$$user_value_r
=
''
; };
my
$insort_b
=
$frame
->Button(
-text
=>
"insort"
,
-command
=>
$insort_sub
,
)->
pack
(
-side
=>
'left'
,
@fxe1
);
$balloon
->attach(
$insort_b
,
-msg
=>
'enter a value, and click the insort button to insert '
.
'this value while keeping the list sorted'
);
return
$insort_b
;
}
sub
insort_entry {
my
$cw
=
shift
;
my
$add
=
shift
;
$logger
->debug(
"insort_entry: $add"
);
return
unless
length
(
$add
);
$cw
->try_and_redraw(
sub
{
$cw
->{list}->insort(
$add
); } );
}
sub
try_and_redraw {
my
$cw
=
shift
;
my
$to_try
=
shift
;
my
$tklist
=
$cw
->{tklist};
my
$list
=
$cw
->{list};
eval
{
$to_try
->(); };
if
($@) {
$cw
->CmeDialog(
-title
=>
"List index error"
,
-text
=> $@->as_string,
)->Show;
}
else
{
$cw
->{store_cb}->();
my
@list
=
$list
->fetch_all_values;
$tklist
->
delete
( 0,
'end'
);
$tklist
->insert( 0,
@list
);
}
return
1;
}
sub
add_set_all_b {
my
(
$cw
,
$frame
,
$b_frame
,
$balloon
,
$user_value_r
) =
@_
;
my
$regexp
=
'\s*,\s*'
;
my
$set_all_sub
=
sub
{
$cw
->set_all_items(
$$user_value_r
,
$regexp
); };
my
$set_bottom
=
$frame
->Frame->
pack
(
@fxe1
,
-side
=>
'bottom'
);
my
$set_b
=
$b_frame
->Button(
-text
=>
"set all"
,
-command
=>
$set_all_sub
,
)->
pack
(
-side
=>
'left'
,
@fx
);
$balloon
->attach(
$set_b
,
-msg
=>
'set all elements with a single string that '
.
'will be split by the regexp displayed below'
);
my
$split_lb
=
$set_bottom
->Label(
-text
=>
'split regexp'
)->
pack
(
-side
=>
'left'
,
@fxe1
);
$set_bottom
->Entry(
-textvariable
=> \
$regexp
)->
pack
(
-side
=>
'left'
,
@fxe1
);
$balloon
->attach(
$split_lb
,
-msg
=>
'regexp used to split the entry above when "set all" button is pressed'
);
return
$set_bottom
;
}
sub
set_all_items {
my
$cw
=
shift
;
my
$data
=
shift
;
my
$regexp
=
shift
;
return
unless
$data
;
my
$tklist
=
$cw
->{tklist};
my
@list
=
split
/
$regexp
/,
$data
;
$tklist
->
delete
( 0,
'end'
);
$tklist
->insert( 0,
@list
);
$cw
->{list}->load_data( \
@list
);
$cw
->{store_cb}->();
}
sub
sort_content {
my
$cw
=
shift
;
my
$tklist
=
$cw
->{tklist};
my
$list
=
$cw
->{list};
$list
->
sort
;
my
@list
=
$list
->fetch_all_values;
$tklist
->
delete
( 0,
'end'
);
$tklist
->insert( 0,
@list
);
$cw
->{store_cb}->();
}
sub
move_up {
my
$cw
=
shift
;
my
$tklist
=
$cw
->{tklist};
my
$from_idx_ref
=
$tklist
->curselection();
return
unless
defined
$from_idx_ref
;
return
unless
@$from_idx_ref
;
my
$from_idx
=
$from_idx_ref
->[0];
return
unless
$from_idx
;
return
unless
$from_idx
> 0;
$cw
->swap(
$from_idx
,
$from_idx
- 1 );
}
sub
move_down {
my
$cw
=
shift
;
my
$tklist
=
$cw
->{tklist};
my
$from_idx_ref
=
$tklist
->curselection();
return
unless
defined
$from_idx_ref
;
return
unless
@$from_idx_ref
;
my
$from_idx
=
$from_idx_ref
->[0];
my
$max_idx
=
$cw
->{list}->fetch_size - 1;
return
unless
$from_idx
<
$max_idx
;
$cw
->swap(
$from_idx
,
$from_idx
+ 1 );
}
sub
swap {
my
(
$cw
,
$ida
,
$idb
) =
@_
;
my
$tklist
=
$cw
->{tklist};
my
$list
=
$cw
->{list};
$list
->swap(
$ida
,
$idb
);
my
$cargo_type
=
$list
->cargo_type;
$tklist
->selectionClear(
$ida
);
if
(
$cargo_type
ne
'node'
) {
my
$old
=
$tklist
->get(
$ida
);
$tklist
->
delete
(
$ida
);
while
(
$idb
>
$tklist
->size ) {
$tklist
->insert(
'end'
,
'<undef>'
);
}
$tklist
->insert(
$idb
,
$old
);
}
$tklist
->selectionSet(
$idb
);
$cw
->{store_cb}->();
}
sub
remove_selection {
my
$cw
=
shift
;
my
$tklist
=
$cw
->{tklist};
my
$list
=
$cw
->{list};
foreach
(
$tklist
->curselection() ) {
$logger
->debug(
"remove_selection: removing index $_"
);
$list
->remove(
$_
);
}
$cw
->{store_cb}->();
$cw
->reset_value;
$cw
->update_warning(
$list
);
}
1;