DepartamentoProdutoList novo arquivo

0:00 / 0:00

O setor de listagem — onde o agente chega quando o usuário clica em "Produtos" no menu lateral do Departamento. É a action CONCRETA que junta TUDO que foi construído até aqui: estende a Action base, usa o WBean como filtro, chama o Model (que herda do DAO) pra buscar os produtos, monta a mesa de listagem com colunas, e devolve o recorte HTML que o browser cola por cima. Oitavo passo da sequência CRUD READ.

Nota: esta fase CRUD READ tem uma listagem SIMPLES — 4 colunas (Nome, Valor, Qtd, Observação), ordenada por nome, sem paginação visível (setPageSize(9999)), sem tabs, sem busca rápida. As funcionalidades mais avançadas (paginação, tabs de status, busca rápida, ordenação por coluna) vão aparecer conforme forem necessárias em sequências futuras.

CÓDIGO COMPLETO
package br.xt.app.departamento.produto;

import br.jasap.core.Effect;
import br.jasap.effect.Response;
import br.jasap.gui.JasapPage;
import br.jasap.gui.ListColumn;
import br.jasap.gui.ListLine;
import br.jasap.gui.ListView;
import br.jasap.gui.Table;
import br.xt.acore.view.XtPage;

public class DepartamentoProdutoList extends DepartamentoProdutoAction {

    @Override
    public Effect execute() throws Exception {
        render();
        return new Response();
    }

    public void render() throws Exception {
        XtPage page = new XtPage(getManager());
        if (isAjaxCall()) {
            update(JasapPage.DIV_WINDOW, page.content(window().toHtml()));
        } else {
            page.getTable()
                    .setBorder(4)
                    .rowC("100%")
                    .setContent(page.content(window().toHtml()))
                    .setStyle(ui().stretchBorder());
            page.setWinTitle("Produtos");
            getOutput().write(this, page);
        }
    }

    public Table window() throws Exception {
        Table w = new Table(getManager()).setSize("100%", "100%");
        w.rowC("99%", JasapPage.DIV_WSPACE, lView());
        w.rowC("1%",  null, ui().line());
        return w;
    }

    private ListView lv = null;
    public ListView lView() throws Exception {
        if (lv == null) {
            lv = ui().lView();

            lv.setOrderBy(DepartamentoProdutoBean.NOME_PRODUTO);
            lv.setPageSize(9999);

            lv.setFiltro(getFiltro());
            getFactory().departamento().proModel().daoList(lv.getData());

            ListColumn col_nome = lv.newColumn("Nome").setWidth(220).setPadding(";padding:10 8 10 8;");
            ListColumn col_vl   = lv.newColumn("Valor").setWidth(100).setPadding(";padding:10 8 10 8;").alignCenter();
            ListColumn col_qtd  = lv.newColumn("Qtd").setWidth(80).setPadding(";padding:10 8 10 8;").alignCenter();
            ListColumn col_obs  = lv.newColumn("Observação").setPadding(";padding:10 8 10 8;");

            while (lv.hasNext()) {
                DepartamentoProdutoBean bean = (DepartamentoProdutoBean) lv.next();
                ListLine line = lv.createLine();
                col_nome.setContent(bean.getNome_produto());
                col_vl.setContent(bean.getVl_produto());
                col_qtd.setContent(bean.getQtd_produto());
                col_obs.setContent(bean.getObs_produto());
                lv.addLine(line);
            }
        }
        return lv;
    }

    public DepartamentoProdutoWBean getFiltro() throws Exception {
        DepartamentoProdutoWBean filtro = (DepartamentoProdutoWBean) getSession().getObject(FILTRO);
        if (filtro == null) {
            filtro = proWBean();
            getSession().addObj(FILTRO, filtro);
        }
        return filtro;
    }

    public static final String LIST   = ROOT.concat("__LIST/");
    public static final String FILTRO = LIST.concat("__FILTRO");

}
Dois caminhos: primeira visita vs clique de menu (Ajax)

O método render() tem um if (isAjaxCall()) que separa dois cenários:

CenárioQuandoO que faz
Não-AjaxPrimeira visita à URL (raro — chegaria pela recepção antes)Monta a página inteira com layout completo via page.getTable() + setStyle + setWinTitle. Escreve o documento HTML INTEIRO na resposta via getOutput().write()
AjaxCaminho normal — clique em "Produtos" no menu lateral dispara via preAjax do HomeEnvia só um RECORTE via update(JasapPage.DIV_WINDOW, ...). O browser cola o recorte por cima da tela atual — não troca a página

A janela em si (window()) é a MESMA nos dois casos — só muda como é entregue.

A janela — window()

Cria um Table (que é o "container" visual) com tamanho 100% × 100%, e divide em duas linhas:

  • Linha superior (99%): a ListView propriamente dita. O parâmetro JasapPage.DIV_WSPACE é o ID do DIV onde o framework vai renderizar
  • Linha inferior (1%): uma linha horizontal (ui().line()) que dá um acabamento visual
A lista — lView() e lazy initialization

Mesmo padrão que a gente viu no proWBean (Action base) e no proModel (MdFactory): o campo privado lv começa null, o método lView() verifica se é a primeira chamada, fabrica na primeira e reusa nas seguintes.

A fabricação da ListView é longa porque ela tem várias etapas:

  1. ui().lView() — fábrica devolve uma ListView vazia
  2. setOrderBy(NOME_PRODUTO) — define a ordem padrão
  3. setPageSize(9999) — sem paginação visível nesta fase (depois vai ser refinado)
  4. setFiltro(getFiltro()) — injeta o WBean (ficha de filtro) na ListView
  5. getFactory().departamento().proModel().daoList(lv.getData()) — aqui é a chamada CENTRAL. Passa pela ferramentaria central, entra na ferramentaria do Departamento, pega o Model, chama daoList. A lista é preenchida com beans do almoxarifado
  6. Cria as 4 colunas (Nome, Valor, Qtd, Observação) com larguras e paddings
  7. Itera while(lv.hasNext()) e monta uma linha pra cada bean, preenchendo as colunas com os getters
Por que o WBean fica na SESSÃO?

O getFiltro() guarda o WBean na ficha permanente da sessão. Por quê?

Porque o filtro PRECISA persistir ENTRE requests. Exemplo: o usuário clica numa aba (futura) "Em Estoque" — isso altera o filtro. Depois muda a página. Depois ordena por coluna. Cada uma dessas ações dispara um request NOVO, com um agente NOVO, um cartão NOVO. Se o filtro não estivesse na sessão, ele ia zerar a cada request.

O getFiltro(): primeira vez, cria um WBean vazio via proWBean() (herdado da Action base) e GUARDA na sessão com a chave FILTRO. Requests seguintes: acha o WBean na sessão e devolve o mesmo — com os filtros que foram acumulados em chamadas anteriores.

Nesta fase CRUD READ o filtro não muda — mas a infraestrutura tá pronta.

As constantes de sessão: LIST e FILTRO

São chaves únicas no mapa global de sessão. Partem do ROOT (herdado da Action base):

ROOT   = "...DEPARTAMENTO__PRODUTO/"
LIST   = ROOT + "__LIST/"
FILTRO = LIST + "__FILTRO"
→ "...DEPARTAMENTO__PRODUTO/__LIST/__FILTRO"

Ter o caminho composto garante que o filtro da listagem de Produto do Departamento não conflita com nenhuma outra chave de sessão em nenhum outro lugar do sistema.

@Override — o que é?

A anotação @Override acima do execute() é uma sinalização pro compilador: "esse método está SOBRESCREVENDO um método da classe-pai". A classe-pai (herdada em cadeia até JasapAct) tem um execute() abstrato — cada action concreta é obrigada a fornecer sua versão.

Se você digitasse excute (com typo) em vez de execute, o Java criaria um método novo em vez de sobrescrever. O @Override manda o compilador reclamar: "você jurou que estava sobrescrevendo algo, mas não existe método com esse nome na classe-pai — provavelmente um typo".

Protege contra erros silenciosos. Sempre usar quando for sobrescrever.

execute() e render()

O execute() é o ponto de entrada oficial da action — todo setor tem esse método. Aqui ele é minimalista: chama render() e devolve new Response() (um objeto vazio que sinaliza "terminei, pode mandar a resposta").

O render() é onde a lógica de montagem da tela mora. Separar em dois métodos permite que outras actions (como futuras inner classes de Sort, QuickSearch, DeleteFromList) chamem render() direto sem passar pelo execute().

getFactory().departamento().proModel().daoList(lv.getData())

A linha central da listagem. Nela acontece todo o fio do cartão temporário:

  1. getFactory() — devolve a AppsRootModelFactory configurada com o cartão
  2. .departamento() — ferramentaria central cria a ferramentaria local do Departamento passando o cartão
  3. .proModel() — ferramentaria local fabrica o Model (na primeira chamada), passando o cartão pro construtor
  4. .daoList(lv.getData()) — chama o método herdado do DAO. A ListView tem uma lista vazia internamente (lv.getData()) que será preenchida com os beans