Group
Extension

App-DBBrowser/lib/App/DBBrowser/Opt/Set.pm

package # hide from PAUSE
App::DBBrowser::Opt::Set;

use warnings;
use strict;
use 5.016;

use Encode                qw( decode );
use File::Basename        qw( fileparse );
use File::Spec::Functions qw( catfile );
use FindBin               qw( $RealBin $RealScript );
#use Pod::Usage            qw( pod2usage ); # required

use Encode::Locale qw();

use Term::Choose       qw();
use Term::Choose::Util qw( insert_sep );
use Term::Form         qw();

use App::DBBrowser::Auxil;
use App::DBBrowser::Opt::DBSet;
use App::DBBrowser::Opt::Get;

sub new {
    my ( $class, $info, $options ) = @_;
    bless {
        i => $info,
        o => $options,
        avail_operators => [
            " = ", " != ", " <> ", " < ", " > ", " >= ", " <= ",
            "REGEXP", "REGEXP_i", "NOT REGEXP", "NOT REGEXP_i", "LIKE", "NOT LIKE",
            "IS NULL", "IS NOT NULL", "IN", "NOT IN", "BETWEEN", "NOT BETWEEN",
            "ANY", "ALL",
        ],
    }, $class;
}

sub _groups {
    my $groups = [
        { name => 'group_plugins',      text => "  Plugins"   },
        { name => 'group_database',     text => "- DB Settings"  },
        { name => 'group_extensions',   text => "- Extensions"   },
        { name => 'group_sql_settings', text => "- SQL Settings" },
        { name => 'group_create',       text => "- Create Table" },
        { name => 'group_output',       text => "- Output"       },
        { name => 'group_import',       text => "- Import"       },
        { name => 'group_export',       text => "- Export"       },
        { name => 'group_misc',         text => "- Misc"         },
        { name => 'group_help',         text => "  Help"         },
        { name => 'group_path',         text => "  Path"         },
    ];
    return $groups;
}


sub _options {
    my ( $group_name ) = @_;
    my $groups = {
        group_help => [
            { name => 'help', text => '', section => '' }
        ],
        group_path => [
            { name => 'path', text => '', section => '' }
        ],
        group_plugins => [
            { name => 'plugins', text => '',  section => 'G' },
        ],
        group_database => [
            { name => '_db_defaults', text => '', section => ''  },
        ],
        group_extensions => [
            { name => '_e_table',        text => "- Tables menu",        section => 'enable' },
            { name => '_e_join',         text => "- Join menu",          section => 'enable' },
            { name => '_e_union',        text => "- Union menu",         section => 'enable' },
            { name => '_e_expressions',  text => "- Columns and Values", section => 'enable' },
            { name => '_e_write_access', text => "- Write access",       section => 'enable' },
        ],
        group_sql_settings => [
            { name => '_meta',               text => "- System data",          section => 'G'      },
            { name => 'operators',           text => "- Operators",            section => 'G'      },
            { name => '_add_aliases',        text => "- Add aliases",          section => 'alias'  },
            { name => '_aliases_in_clauses', text => "- Alias use in clauses", section => 'alias'  },
            { name => '_sql_identifiers',    text => "- Identifiers",          section => 'G'      },
            { name => '_view_name_prefix',   text => "- View prefix",          section => 'create' }, ##
            { name => '_other_sql_settings', text => "- Other",                section => 'G'      },
        ],
        group_create => [
            { name => '_enable_ct_opt',          text => "- Enable options",                     section => 'create' },
            { name => '_add_ct_fields',          text => "- Add form fields",                    section => 'create' },
            { name => '_default_ai_column_name', text => "- Default auto increment column name", section => 'create' },
        ],
        group_output => [
            { name => '_binary_filter',    text => "- Binary filter",       section => 'table' },
            { name => '_squash_spaces',    text => "- Squash spaces",       section => 'table' },
            { name => '_base_indent',      text => "- Indentation",         section => 'G'     },
            { name => '_set_string',       text => "- Undef string",        section => 'table' },
            { name => '_warningss',        text => "- Warnings",            section => 'G'     },
            { name => 'progress_bar',      text => "- Progress bar",        section => 'table' },
            { name => 'tab_width',         text => "- Tab width",           section => 'table' },
            { name => '_pad_row_edges',    text => "- Pad row edges",       section => 'table' },
            { name => 'max_width_exp',     text => "- Max width expanded",  section => 'table' },
            { name => '_color',            text => "- Color",               section => 'table' },
            { name => 'trunc_fract_first', text => "- Trunc fract first",   section => 'table' },
            { name => 'min_col_width',     text => "- Trunc col threshold", section => 'table' },
        ],
        group_import => [
            { name => '_parse_file',        text => "- Parse tool",        section => 'insert' },
            { name => '_csv_in_char',       text => "- CSV options in a",  section => 'csv_in' },
            { name => '_csv_in_options',    text => "- CSV options in b",  section => 'csv_in' },
            { name => '_split_config',      text => "- Settings 'split'",  section => 'split'  },
            { name => '_input_filter',      text => "- Input filter",      section => 'insert' },
            { name => '_empty_to_null',     text => "- Empty to Null",     section => 'insert' },
            { name => '_file_encoding_in',  text => "- File encoding in",  section => 'insert' },
            { name => 'history_dirs',       text => "- Directory history", section => 'insert' },
            { name => '_file_filter',       text => "- File filter",       section => 'insert' },
            { name => '_show_hidden_files', text => "- Hidden files",      section => 'insert' },
            { name => '_data_source_type',  text => "- Source type",       section => 'insert' },
        ],
        group_export => [
            { name => 'export_dir',         text => "- Destination folder", section => 'export'  },
            { name => '_exported_files',    text => "- File name",          section => 'export'  },
            { name => '_csv_out_char',      text => "- CSV options out a",  section => 'csv_out' },
            { name => '_csv_out_options',   text => "- CSV options out b",  section => 'csv_out' },
            { name => '_file_encoding_out', text => "- File encoding out",  section => 'export'  },
        ],
        group_misc => [
            { name => '_menu_memory',  text => "- Menu memory",  section => 'G'     },
            { name => '_table_expand', text => "- Expand table", section => 'table' },
            { name => '_search',       text => "- Search",       section => 'table' },
            { name => '_mouse',        text => "- Mouse mode",   section => 'table' },
            { name => '_db2_encoding', text => "- DB2 encoding", section => 'G'     },
        ],
    };
    return $groups->{$group_name};
}


sub set_options {
    my ( $sf, $arg_group ) = @_;
    if ( ! $sf->{o} || ! %{$sf->{o}} ) {
        my $opt_get = App::DBBrowser::Opt::Set->new( $sf->{i}, $sf->{o} );
        $sf->{o} = $opt_get->read_config_files();
    }
    my $tc = Term::Choose->new( $sf->{i}{tc_default} );
    my $groups;
    if ( $arg_group ) {
        if ( $arg_group eq 'create' ) {
            $groups = [ { name => 'group_create', text => '' } ];
        }
        elsif ( $arg_group eq 'import' ) {
            $groups = [ { name => 'group_import', text => '' } ];
        }
        elsif ( $arg_group eq 'export' ) {
            $groups = [ { name => 'group_export', text => '' } ];
        }
        else {
            die "'$arg_group' invalid argument";
        }
    }
    else {
        $groups = _groups();
    }
    my $grp_old_idx = 0;

    GROUP: while( 1 ) {
        my ( $group_name, $group_text );
        if ( @$groups == 1 ) {
            $group_name = $groups->[0]{name};
            $group_text = $groups->[0]{text};
        }
        else {
            my @pre  = ( undef, $sf->{i}{_continue} );
            my $menu = [ @pre, map( $_->{text}, @$groups ) ];
            # Choose
            my $grp_idx = $tc->choose(
                $menu,
                { %{$sf->{i}{lyt_v}}, index => 1, default => $grp_old_idx, undef => $sf->{i}{_quit} }
            );
            if ( ! $grp_idx ) {
                if ( $sf->{write_config} ) {
                    $sf->__write_config_files();
                    delete $sf->{write_config};
                }
                exit();
            }
            if ( $sf->{o}{G}{menu_memory} ) {
                if ( $grp_old_idx == $grp_idx && ! $ENV{TC_RESET_AUTO_UP} ) {
                    $grp_old_idx = 0;
                    next GROUP;
                }
                $grp_old_idx = $grp_idx;
            }
            else {
                if ( $grp_old_idx != 0 ) {
                    $grp_old_idx = 0;
                    next GROUP;
                }
            }
            if ( $menu->[$grp_idx] eq $sf->{i}{_continue} ) {
                if ( $sf->{write_config} ) {
                    $sf->__write_config_files();
                    delete $sf->{write_config};
                }
                return $sf->{o};
            }
            $group_name = $groups->[$grp_idx-@pre]{name};
            $group_text = $groups->[$grp_idx-@pre]{text};
        };
        my $group_prompt;
        if ( length $group_text ) {
            $group_prompt = $group_text =~ s/^- //r . ':';
        }
        my $options = _options( $group_name );
        my $opt_old_idx = 0;

        OPTION: while ( 1 ) {
            my ( $section, $opt );
            if ( @$options == 1 ) {
                $section = $options->[0]{section};
                $opt = $options->[0]{name};
            }
            else {
                my @pre  = ( undef );
                my $menu = [ @pre, map( $_->{text}, @$options ) ];
                # Choose
                my $opt_idx = $tc->choose(
                    $menu,
                    { %{$sf->{i}{lyt_v}}, prompt => $group_prompt,
                      index => 1, default => $opt_old_idx, undef => '  <=' }
                );
                if ( ! $opt_idx ) {
                    if ( @$groups == 1 ) {
                        if ( $sf->{write_config} ) {
                            $sf->__write_config_files();
                            delete $sf->{write_config};
                        }
                        return $sf->{o};
                    }
                    next GROUP;
                }
                if ( $sf->{o}{G}{menu_memory} ) {
                    if ( $opt_old_idx == $opt_idx && ! $ENV{TC_RESET_AUTO_UP} ) {
                        $opt_old_idx = 0;
                        next OPTION;
                    }
                    $opt_old_idx = $opt_idx;
                }
                else {
                    if ( $opt_old_idx != 0 ) {
                        $opt_old_idx = 0;
                        next OPTION;
                    }
                }
                $section = $options->[$opt_idx-@pre]{section};
                $opt = $options->[$opt_idx-@pre]{name};
            }
            my ( $no, $yes ) = ( 'NO', 'YES' );
            if ( $opt eq 'help' ) {
                require Pod::Usage;  # ctrl-c
                Pod::Usage::pod2usage( { -exitval => 'NOEXIT', -verbose => 2 } );
            }
            elsif ( $opt eq 'path' ) {
                my $app_dir = $sf->{i}{app_dir};
                eval { $app_dir = decode( 'locale', $app_dir ) };
                my $info = 'db-browser'  . "\n\n";
                $info .= 'version: ' . $main::VERSION . "\n\n";
                $info .= 'path: ' . catfile( $RealBin, $RealScript ) . "\n\n";
                $info .= 'app-dir: ' . $app_dir . "\n";
                $tc->choose( [ '<<' ], { prompt => $info, color => 1 } );
            }
            elsif ( $opt eq 'plugins' ) {
                my %installed_driver;
                for my $dir ( @INC ) {
                    my $glob_pattern = catfile $dir, 'App', 'DBBrowser', 'DB', '*.pm';
                    map { $installed_driver{( fileparse $_, '.pm' )[0]}++ } glob $glob_pattern;
                }
                my $prompt = "\n" . 'Database plugins:';
                $sf->__choose_a_subset_wrap( $section, $opt, [ sort keys %installed_driver ], $prompt );
            }
            elsif ( $opt eq '_db_defaults' ) {
                my $odb = App::DBBrowser::Opt::DBSet->new( $sf->{i}, $sf->{o} );
                $odb->database_setting();
            }
            ##### Extensions #####
            elsif ( $opt eq '_e_table' ) {
                my $prompt = 'Extend Tables Menu:';
                my $sub_menu = [
                    [ 'm_derived',   "- Add Subquery",      [ $no, $yes ] ],
                    [ 'm_cte',       "- Add Cte",         [ $no, $yes ] ],
                    [ 'join',        "- Add Join",        [ $no, $yes ] ],
                    [ 'union',       "- Add Union",       [ $no, $yes ] ],
                    [ 'db_settings', "- Add DB settings", [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_e_join' ) {
                my $prompt = 'Extend Join Menu:';
                my $sub_menu = [
                    [ 'j_derived', "- Add Subquery", [ $no, $yes ] ],
                    [ 'j_cte',     "- Add Cte",      [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_e_union' ) {
                my $prompt = 'Extend Union Menu:';
                my $sub_menu = [
                    [ 'u_derived',     "- Add Subquery",   [ $no, $yes ] ],
                    [ 'u_cte',         "- Add Cte",        [ $no, $yes ] ],
                    [ 'u_edit_stmt',   "- Edit Statement", [ $no, $yes ] ],
                    [ 'u_parentheses', "- Parentheses",    [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_e_expressions' ) {
                my $prompt = 'Extended expressions:';
                my $sub_menu = [
                    [ 'extended_cols',   "- Exdented Columns",    [ $no, $yes ] ],
                    [ 'extended_values', "- Exdented Values",     [ $no, $yes ] ],
                    [ 'extended_args',   "- Exdented Arguments",  [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_e_write_access' ) {
                my $prompt = 'Write access: ';
                my $sub_menu = [
                    [ 'insert_into',  "- Insert Records", [ $no, $yes ] ],
                    [ 'update',       "- Update Records", [ $no, $yes ] ],
                    [ 'delete',       "- Delete Records", [ $no, $yes ] ],
                    [ 'create_table', "- Create Table",   [ $no, $yes ] ],
                    [ 'drop_table',   "- Drop   Table",   [ $no, $yes ] ],
                    [ 'create_view',  "- Create View",    [ $no, $yes ] ],
                    [ 'drop_view',    "- Drop   View",    [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            ##### SQL Settings #####
            elsif ( $opt eq '_meta' ) {
                my $prompt = 'System data ';
                my $sub_menu = [
                    [ 'metadata', "- Show system DB/Schemas/Tables", [ $no, $yes ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq 'operators' ) {
                my $prompt = 'Choose operators';
                $sf->__choose_a_subset_wrap( $section, $opt, $sf->{avail_operators}, $prompt );
            }
            elsif ( $opt eq '_add_aliases' ) {
                my $prompt = 'Add alias:';
                my $sub_menu = [
                    [ 'complex_cols_select', "- Functions/Subqueries in select",  [ 'NO',   undef, 'ASK',   undef     ] ],
                    [ 'tables_in_join',      "- Tables in join",                  [ undef, 'AUTO',  undef, 'ASK/AUTO' ] ],
                    [ 'join_columns',        "- Non-unique columns in join",      [ 'NO',  'AUTO', 'ASK',  'ASK/AUTO' ] ],
                    [ 'derived_table',       "- Derived table",                   [ 'NO',  'AUTO', 'ASK',  'ASK/AUTO' ] ],
                    [ 'ordinary_table',      "- Ordinary table",                  [ 'NO',  'AUTO', 'ASK',  'ASK/AUTO' ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_aliases_in_clauses' ) {
                my $prompt = 'Use aliases in: ';
                my $sub_menu = [
                    [ 'use_in_group_by', "- Group by", [ $no, $yes ] ],
                    [ 'use_in_having',   "- Having",   [ $no, $yes ] ],
                    [ 'use_in_order_by', "- Order by", [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_sql_identifiers' ) {
                my $prompt = 'Your choice: ';
                my $sub_menu = [
                    [ 'qualified_table_name', "- Qualified table names", [ $no, $yes ] ],
                    [ 'quote_tables',         "- Quote table names",     [ $no, $yes ] ],
                    [ 'quote_columns',        "- Quote column names",    [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_view_name_prefix' ) {
                my $items = [
                    { name => 'view_name_prefix', prompt => "View name prefix" },
                ];
                my $prompt = 'Set a view name prefix';
                $sf->__group_readline( $section, $items, $prompt );
            }
            elsif ( $opt eq '_other_sql_settings' ) {
                my $prompt = 'Your choice: ';
                my $sub_menu = [
                    #[ 'limit_fetch_col_names', "- Fetch column names with LIMIT 0", [ $no, $yes ] ], ##
                    [ 'edit_sql_menu_sq',      "- Subqueries created with 'SQL Menu': Allow editing.", [ $no, $yes ] ],
                    [ 'pg_autocast',           "- Pg: Convert to 'text' automatically when required.", [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            ##### Create table ####
            elsif ( $opt eq '_enable_ct_opt' ) {
                my $prompt = 'Activate options';
                my $sub_menu = [
                    [ 'option_ai_column_enabled', "- Option 'Auto Increment'", [ $no, $yes ] ],
                    [ 'data_type_guessing',       "- Data type guessing",      [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_add_ct_fields' ) {
                my $prompt = 'Add fields';
                my $sub_menu = [
                    [ 'table_constraint_rows',    "- Table constraint fields", [ 0 .. 9    ] ],
                    [ 'table_option_rows',        "- Table option fields",     [ 0 .. 9    ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_default_ai_column_name' ) {
                my $items = [
                    { name => 'default_ai_column_name', prompt => "Default primary key auto increment column name" },
                ];
                my $prompt = 'Set a default auto increment column name';
                $sf->__group_readline( $section, $items, $prompt );
            }
            ##### Output ####
            elsif ( $opt eq 'min_col_width' ) {
                my $digits = 3;
                my $prompt = 'Set the minimum column width ';
                $sf->__choose_a_number_wrap( $section, $opt, $prompt, $digits, 0 );
            }
            elsif ( $opt eq 'trunc_fract_first' ) {
                my $prompt = 'If the terminal not wide enough:';
                my $sub_menu = [
                    [ 'trunc_fract_first', "- First step: truncate fraction of numbers", [ $no, $yes ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq 'progress_bar' ) {
                my $digits = 7;
                my $prompt = 'Set the threshold for the progress bar ';
                $sf->__choose_a_number_wrap( $section, $opt, $prompt, $digits, 0 );
            }
            elsif ( $opt eq 'tab_width' ) {
                my $digits = 3;
                my $prompt = 'Set the tab width ';
                $sf->__choose_a_number_wrap( $section, $opt, $prompt, $digits, 0 );
            }
            elsif ( $opt eq 'max_width_exp' ) {
                my $digits = 3;
                my $prompt = 'Maximum width expanded table row';
                $sf->__choose_a_number_wrap( $section, $opt, $prompt, $digits, 0 );
            }
            elsif ( $opt eq '_pad_row_edges' ) {
                my $prompt = '"Pad row edges"';
                my $sub_menu = [
                    [ 'pad_row_edges', "- Pad row edges with a space.", [ $no, $yes ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_color' ) {
                my $prompt = '"ANSI color escapes"';
                my $sub_menu = [
                    [ 'color', "- ANSI color escapes", [ $no, $yes ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_binary_filter' ) {
                my $prompt = 'How to print arbitrary binray data';
                my $sub_menu = [
                    [ 'binary_filter', "- Binary filter", [ $no, 'BNRY', 'Hexadecimal' ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_squash_spaces' ) {
                my $prompt = 'Remove leading and trailing spaces and squash consecutive spaces';
                my $sub_menu = [
                    [ 'squash_spaces', "- Squash spaces", [ $no, $yes ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_base_indent' ) {
                my $prompt = 'Set the indentation width for SQL substatements';
                my $sub_menu = [
                    [ 'base_indent', "- Indentation", [ 0, 1, 2, 3, 4 ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_set_string' ) {
                my $items = [
                    { name => 'undef', prompt => "Show undefined fields as" },
                ];
                my $prompt = 'Undef string';
                $sf->__group_readline( $section, $items, $prompt );
            }
            elsif ( $opt eq '_warningss' ) {
                my $prompt = '"Disable/Enable warnings"';
                my $sub_menu = [
                    [ 'file_find_warnings',   "- Warnings \"File::Find\" (SQLite)", [ $no, $yes ] ],
                    [ 'warnings_table_print', "- Warnings table-print",             [ $no, $yes ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            ##### Import #####
            elsif ( $opt eq '_data_source_type' ) {
                my $prompt = 'Data source options';
                my $sub_menu = [
                    [ 'data_source_create_table', "- Data source \"Create table\"", [ 'plain', 'file', 'menu' ], ],
                    [ 'data_source_insert',       "- Data source \"Insert into\"",  [ 'plain', 'file', 'menu' ], ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_parse_file' ) {
                my $prompt = 'How to parse input files';
                my $sub_menu = [
                    [ 'parse_mode_input_file', "- Use", [ 'Text::CSV', 'split', 'Template', 'Spreadsheet::Read' ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_csv_in_char' ) {
                my $items = [
                    { name => 'sep_char',    prompt => "sep_char   " },
                    { name => 'quote_char',  prompt => "quote_char " },
                    { name => 'escape_char', prompt => "escape_char" },
                    { name => 'eol',         prompt => "eol        " },
                    { name => 'comment_str', prompt => "comment_str" },
                ];
                my $prompt = 'Text::CSV_XS read options a';
                $sf->__group_readline( $section, $items, $prompt );
            }
            elsif ( $opt eq '_csv_in_options' ) {
                my $prompt = 'Text::CSV_XS read options b';
                my $sub_menu = [
                    [ 'allow_loose_escapes', "- allow_loose_escapes", [ $no, $yes ] ],
                    [ 'allow_loose_quotes',  "- allow_loose_quotes",  [ $no, $yes ] ],
                    [ 'allow_whitespace',    "- allow_whitespace",    [ $no, $yes ] ],
                    [ 'blank_is_undef',      "- blank_is_undef",      [ $no, $yes ] ],
                    [ 'binary',              "- binary",              [ $no, $yes ] ],
                    [ 'decode_utf8',         "- decode_utf8",         [ $no, $yes ] ],
                    [ 'empty_is_undef',      "- empty_is_undef",      [ $no, $yes ] ],
                    [ 'skip_empty_rows',     "- skip_empty_rows",     [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_split_config' ) {
                my $items = [
                    { name => 'field_sep',     prompt => "Field separator  " },
                    { name => 'field_l_trim',  prompt => "Trim field left  " },
                    { name => 'field_r_trim',  prompt => "Trim field right " },
                    { name => 'record_sep',    prompt => "Record separator " },
                    { name => 'record_l_trim', prompt => "Trim record left " },
                    { name => 'record_r_trim', prompt => "Trim record right" },
                ];
                my $prompt = 'Config \'split\' mode';
                $sf->__group_readline( $section, $items, $prompt );
            }
            elsif ( $opt eq '_input_filter' ) {
                my $prompt = 'Enable input filter';
                my $sub_menu = [
                    [ 'enable_input_filter', "- Enable input filter", [ $no, $yes ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_empty_to_null' ) {
                my $prompt = 'Enable "Empty to NULL":';
                my $sub_menu = [
                    [ 'empty_to_null_plain',  "- Source type 'plain'",  [ $no, $yes ] ],
                    [ 'empty_to_null_file',   "- Source type 'file'",   [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_file_encoding_in' ) {
                my $items = [
                    { name => 'file_encoding', prompt => "Input file encoding" },
                ];
                my $prompt = 'Encoding of input data text files';
                $sf->__group_readline( $section, $items, $prompt );
            }
            elsif ( $opt eq 'history_dirs' ) {
                my $digits = 2;
                my $prompt = 'Number of saved dirs: ';
                $sf->__choose_a_number_wrap( $section, $opt, $prompt, $digits, 1 );
            }
            elsif ( $opt eq '_file_filter' ) {
                my $items = [
                    { name => 'file_filter', prompt => "File filter glob pattern" },
                ];
                my $prompt = 'Set the glob pattern for the file filter';
                $sf->__group_readline( $section, $items, $prompt );
            }
            elsif ( $opt eq '_show_hidden_files' ) {
                my $prompt = 'Show hidden files';
                my $sub_menu = [
                    [ 'show_hidden_files', "- Show hidden files", [ $no, $yes ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            ##### Export #####
            elsif ( $opt eq 'export_dir' ) {
                my $prompt = 'Choose destination folder for data exported in CSV-files';
                $sf->__choose_a_directory_wrap( $section, $opt, $prompt );
            }
            elsif ( $opt eq '_exported_files' ) {
                my $prompt = 'Exported files';
                my $sub_menu = [
                    [ 'add_extension',      "- Add automatically '.csv'-extension", [ $no, $yes ] ],
                    [ 'default_filename',   "- Table-name is default file-name", [ $no, $yes ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_file_encoding_out' ) {
                my $items = [
                    { name => 'file_encoding', prompt => "Encoding CSV file" },
                ];
                my $prompt = 'Data to CSV-files';
                $sf->__group_readline( $section, $items, $prompt );
            }
            elsif ( $opt eq '_csv_out_char' ) {
                my $items = [
                    { name => 'sep_char',    prompt => "sep_char   " },
                    { name => 'quote_char',  prompt => "quote_char " },
                    { name => 'escape_char', prompt => "escape_char" },
                    { name => 'eol',         prompt => "eol        " },
                    { name => 'undef_str',   prompt => "undef_str"   },
                ];
                my $prompt = 'Text::CSV_XS write options a';
                $sf->__group_readline( $section, $items, $prompt );
            }
            elsif ( $opt eq '_csv_out_options' ) {
                my $prompt = 'Text::CSV_XS write options b';
                my $sub_menu = [
                    [ 'always_quote', "- always_quote", [ $no, $yes ] ],
                    [ 'binary',       "- binary",       [ $no, $yes ] ],
                    [ 'escape_null',  "- escape_null",  [ $no, $yes ] ],
                    [ 'quote_binary', "- quote_binary", [ $no, $yes ] ],
                    [ 'quote_empty',  "- quote_empty",  [ $no, $yes ] ],
                    [ 'quote_space',  "- quote_space",  [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            ##### misc #####
            elsif ( $opt eq '_menu_memory' ) {
                my $prompt = 'Your choice: ';
                my $sub_menu = [
                    [ 'menu_memory', "- Menu memory", [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_table_expand' ) {
                my $prompt = 'Your choice: ';
                my $sub_menu = [
                    [ 'table_expand', "- Expand table rows",   [ $no, $yes ] ],
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_search' ) {
                my $prompt = 'Your choice: ';
                my $sub_menu = [
                    [ 'search', "- Row filter", [ 'disabled', 'case insensitive', 'case sensitive' ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_mouse' ) {
                my $prompt = 'Your choice: ';
                my $sub_menu = [
                    [ 'mouse', "- Mouse mode", [ $no, $yes ] ]
                ];
                $sf->__settings_menu_wrap( $section, $sub_menu, $prompt );
            }
            elsif ( $opt eq '_db2_encoding' ) {
                my $items = [
                    { name => 'db2_encoding', prompt => "DB2 application code set" },
                ];
                my $prompt = 'Set the DB2 application code set';
                $sf->__group_readline( $section, $items, $prompt );
            }
            else {
                die "Unknown option: $opt";
            }
            if ( @$options == 1 ) {
                if ( @$groups == 1 ) {
                    if ( $sf->{write_config} ) {
                        $sf->__write_config_files();
                        delete $sf->{write_config};
                    }
                    return $sf->{o};
                }
                else {
                    next GROUP;
                }
            }
        }
    }
}


sub __settings_menu_wrap {
    # sets the options to the index of the chosen values, not to the values itself
    my ( $sf, $section, $sub_menu, $prompt ) = @_;
    my $tu = Term::Choose::Util->new( $sf->{i}{tcu_default} );
    my $changed = $tu->settings_menu(
        $sub_menu, $sf->{o}{$section},
        { prompt => $prompt, back => $sf->{i}{_back}, confirm => $sf->{i}{_confirm} }
    );
    return if ! $changed;
    $sf->{write_config}++;
}


sub __choose_a_subset_wrap {
    my ( $sf, $section, $opt, $available, $prompt ) = @_;
    my $tu = Term::Choose::Util->new( $sf->{i}{tcu_default} );
    my $current = $sf->{o}{$section}{$opt};
    # Choose_list
    my $info = 'Cur: ' . join( ', ', @$current );
    my $name = 'New: ';
    my $list = $tu->choose_a_subset(
        $available,
        { prompt => $prompt, cs_label => $name, info => $info, prefix => '- ', keep_chosen => 0,
          index => 0, confirm => $sf->{i}{_confirm}, back => $sf->{i}{_back}, layout => 2,
          clear_screen => 1 }
    );
    return if ! defined $list;
    return if ! @$list;
    $sf->{o}{$section}{$opt} = $list;
    $sf->{write_config}++;
    return;
}


sub __choose_a_number_wrap {
    my ( $sf, $section, $opt, $prompt, $digits, $small_first ) = @_;
    my $tu = Term::Choose::Util->new( $sf->{i}{tcu_default} );
    my $current = $sf->{o}{$section}{$opt};
    my $w = $digits + int( ( $digits - 1 ) / 3 ) * length $sf->{i}{info_thsd_sep};
    my $info = 'Cur: ' . sprintf( "%*s", $w, insert_sep( $current, $sf->{i}{info_thsd_sep} ) );
    my $name = 'New: ';
    #$info = $prompt . "\n" . $info;
    # Choose_a_number
    my $choice = $tu->choose_a_number( $digits,
        { prompt => $prompt, cs_label => $name, info => $info, small_first => $small_first,
          clear_screen => 1, confirm => $sf->{i}{confirm}, back => $sf->{i}{back} }
    );
    return if ! defined $choice;
    $sf->{o}{$section}{$opt} = $choice;
    $sf->{write_config}++;
    return;
}


sub __choose_a_directory_wrap {
    my ( $sf, $section, $opt, $prompt ) = @_;
    my $tu = Term::Choose::Util->new( $sf->{i}{tcu_default} );
    #my $current = $sf->{o}{$section}{$opt};
    my $choice = $tu->choose_a_directory(
        { show_hidden => 1, prompt => $prompt, clear_screen => 1, decoded => 1,
          confirm => $sf->{i}{confirm}, back => $sf->{i}{back} } ##
    );
    return if ! defined $choice;
    $sf->{o}{$section}{$opt} = $choice;
    $sf->{write_config}++;
    return;
}


sub __group_readline {
    my ( $sf, $section, $items, $prompt ) = @_;
    my $list = [ map {
        [
            exists $_->{prompt} ? $_->{prompt} : $_->{name},
            $sf->{o}{$section}{$_->{name}}
        ]
    } @{$items} ];
    my $tf = Term::Form->new( $sf->{i}{tf_default} );
    my $new_list = $tf->fill_form(
        $list,
        { prompt => $prompt, confirm => $sf->{i}{confirm}, back => $sf->{i}{back} }
    );
    if ( $new_list ) {
        for my $i ( 0 .. $#$items ) {
            $sf->{o}{$section}{$items->[$i]{name}} = $new_list->[$i][1];
        }
        $sf->{write_config}++;
    }
}


sub __write_config_files {
    my ( $sf ) = @_;
    my $tmp = {};
    for my $section ( keys %{$sf->{o}} ) {
        for my $opt ( keys %{$sf->{o}{$section}} ) {
            $tmp->{$section}{$opt} = $sf->{o}{$section}{$opt};
        }
    }
    my $ax = App::DBBrowser::Auxil->new( $sf->{i}, $sf->{o}, {} );
    my $file_name_fs = $sf->{i}{f_settings};
    $ax->write_json( $file_name_fs, $tmp  );
}




1;


__END__


Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.