// Copyright (C) 2007 Luciano Santos e Ian Schechtman package tirateima.controlador; import java.io.Reader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Stack; import javax.swing.ImageIcon; import javax.swing.JButton; import tirateima.gui.alerta.Alerta; import tirateima.gui.arquivos.GerenciadorArquivos; import tirateima.gui.console.Console; import tirateima.gui.editortexto.EditorTexto; import tirateima.gui.variaveis.Mostrador; import tirateima.parser.ParseException; import tirateima.parser.TiraTeimaParser; /** * Classe que fornece os métodos de controle da execução do programa tirateima * Carrega cada estado que será mostrado em tela a partir de botões definidos e a lista de estados. * @Author Luciano Santos e Ian Schechtman */ public class Controlador { /** Editor de texto.*/ public EditorTexto editorTexto; /** O Mostrador. */ public Mostrador mostrador; /** O console. */ public Console console; /** Os alertas. */ public Alerta alerta; /** O gerador de arquivos. */ public GerenciadorArquivos ga; /** Indica se há jump ou não no passo */ public Boolean jump; /** Indica para qual estado ir em caso de haver jump no passo */ public String jumpTo; public HashMap<String, RecordDefinition> declared_records; public HashMap<String, FunctionDeclaration> declared_functions; /** Botões de navegação. */ private JButton btnAnt; private JButton btnProx; private JButton btnReiniciar; /** Lista sequencial dos passos fornecidos.*/ private List<Step> passos; /** Pilha de estados que guarda a ordem de execução do código. */ private Stack<Estado> estados; /** É o estado atual do Tira-Teima*/ private Estado estado; /** Indice para controle da lista de estados. */ private int indice; /** *Método contrutor único/default. *@param passos Array contendo a lista de estados que o programa executará. *@param mostrador *@param ga Objeto gráfico onde o programa desenhará o menu *@param editor *@param console *@param alerta *@param btnAnt Botao que retorna ao estado anterior *@param btnProx Botao que anvança ao próximo estado *@param btnReiniciar Botao que reinicia a execução *@param btnPular Botao para pular à linha informado pelo usuário na caixa txtLinha *@param txtLinha Caixa de texto que serve de argumento ao botao pular linha. * @throws ParseException * @throws TiraTeimaLanguageException */ public Controlador(Reader arq_texto, Mostrador mostrador, GerenciadorArquivos ga, EditorTexto editorTexto, Console console, Alerta alerta, JButton btnAnt, JButton btnProx, JButton btnReiniciar) throws TiraTeimaLanguageException, ParseException { //cria a lista de estados com label, nro de liha e passo a ser executado passos = parse(arq_texto); //inicializa a pilha de estados executados estados = new Stack<Estado>(); //inicializa o estado atual estado = null; //inicializa os registros e as funções declared_records = new HashMap<String, RecordDefinition>(); declared_functions = new HashMap<String, FunctionDeclaration>(); indice = -1; this.mostrador = mostrador; this.ga = ga; this.editorTexto = editorTexto; this.console = console; this.alerta = alerta; this.jump = Boolean.FALSE; this.jumpTo = null; mostrador.setEstado(null); ga.setEstado(null); editorTexto.setEstado(null); console.setEstado(null); alerta.setEstado(null); /*Botão para estado anterior.*/ this.btnAnt = btnAnt; /*Cria evento.*/ btnAnt.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { try { antEstado(); } catch (TiraTeimaLanguageException e) { e.printStackTrace(); } } }); /*Botão para próximo estado.*/ this.btnProx = btnProx; /*Cria evento.*/ btnProx.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { try { proxEstado(); } catch (TiraTeimaLanguageException e) { e.printStackTrace(); } } }); /*Botão para reiniciar.*/ this.btnReiniciar = btnReiniciar; /*Cria evento.*/ btnReiniciar.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { indice = -1; while(!estados.empty()){ try{ antEstado(); }catch (Exception e) { e.printStackTrace(); } } ajustarBotoes(); } }); ajustarBotoes(); } /** * */ /** * Método ajusta os botoes do controle. * Botão Anterior, Reiniciar -> Ativa quando estiver depois do primeiro estado. * Botão Pular -> Define de forma se ativado ou desativado * Botão Próximo -> No primeiro estado define como o rótulo "Iniciar" e enquanto não estiver no último estado fica ativo com o Rótulo "Próximo" */ private void ajustarBotoes(){ /* Ativar/desativar botão "Anterior" */ btnAnt.setEnabled(indice > 0); btnReiniciar.setEnabled(indice > 0); /* Ativar/desativar botão "Próximo" */ btnProx.setEnabled(indice < passos.size()-1); /* Definir título do botão "Próximo" */ btnProx.setText(indice < 0 ? "Iniciar" : "Próximo"); final ImageIcon iconeIniciar = new ImageIcon(getClass().getResource("/resources/iniciar.png")); final ImageIcon iconeProximo = new ImageIcon(getClass().getResource("/resources/proximo.png")); btnProx.setIcon(indice < 0 ? iconeIniciar : iconeProximo); } /** * Define todos os atributos do objeto estado passado como parâmetro. * @param e Objeto do tipo Estado que terá seus atributos definidos. */ private void setEstado(Estado e){ mostrador.setEstado(e.est_mostrador); editorTexto.setEstado(e.est_editor); console.setEstado(e.est_console); alerta.setEstado(e.est_alerta); ga.setEstado(e.est_ga); if(e.est_jump != null){ jump = (Boolean)e.est_jump; } else{ jump = Boolean.FALSE; } jumpTo = (String)e.est_jumpTo; ajustarBotoes(); } /** * Define o próximo estado incrementando índice e chama método setEstado. * * Caso o fluxo de execução sofra desvio, vai para o estado de label indicado. * Caso o fluxo de execução não tenha sofrido desvio (jump), passa ao estado seguinte. * * * @throws TiraTeimaLanguageException * * @see setEstado */ public void proxEstado () throws TiraTeimaLanguageException{ /*Coloca o estado atual na pilha, caso haja, para ser possível retornar a ele.*/ if(estado != null){ estados.push(estado); } /*Cria um novo estado*/ estado = new Estado(); /*Seleciona o passo*/ Step passo; //Se for jump, pega o passo pelo label. if(jump == Boolean.TRUE){ passo = procuraPassoPorLabel(); indice = passos.indexOf(passo); //Limpa os atributos de jump jump = Boolean.FALSE; jumpTo = null; } //Se não for jump, pega o próximo passo da lista. else if(indice < passos.size()-1){ passo = passos.get(++indice); } //Caso contrário, apenas inicializa a variável, pois os passos acabaram. else{ passo = null; } //Caso os passos não tenham acabado if(passo != null){ try{ /*Executa os commandos relativos ao passo selecionado.*/ for(Command c : passo.commands){ c.execute(this); } /*Destaca a linha do editor correspondente ao passo.*/ editorTexto.getCaixaTexto().setMarcada(passo.line); /*Salva o estado atual do Tira-Teima*/ saveState(estado, passo); /*Seta o estado*/ setEstado(estado); }catch (ExecutionException e) { /*Volta para o estado anterior */ antEstado(); } } //Ajusta os botões ajustarBotoes(); } /** * Define o estado anterior decrementando índice e chama método setEstado * @throws TiraTeimaLanguageException * @see setEstado */ public void antEstado () throws TiraTeimaLanguageException{ /*Retira o estado da pilha*/ try{ if(estado != null){ for(Command c : ((Step)(estado.est_passo)).commands){ c.revert(this); } } }catch(ExecutionException e){ e.printStackTrace(); } estado = estados.pop(); indice = passos.indexOf(estado.est_passo); /*Seta o estado no Tira-Teima*/ setEstado(estado); } /** Procura o passo com um label indicado. * @return Step passo */ private Step procuraPassoPorLabel() { String labelPasso; for (Step p : passos) { if (p.label != null){ labelPasso = p.label; if(labelPasso.equals(jumpTo)){ return p; } } } return null; } /** * Salva um estado de acordo com os atributos setados no passo e no gerador. * @param Estado e * @param Step passo */ public void saveState(Estado e, Step passo){ /** Coloca no estado criado a condição de cada elemento gráfico do tirateima. */ e.est_passo = passo; e.est_mostrador = mostrador.getEstado(); e.est_editor = editorTexto.getEstado(); e.est_console = console.getEstado(); e.est_alerta = alerta.getEstado(); e.est_ga = ga.getEstado(); e.est_label = passo.label; if(jumpTo != null){ e.est_jumpTo = jumpTo; } e.est_jump = jump.booleanValue(); } /** * Analisa um arquivo de comandos do Tira-Teima e gera a lista de passos. * Recebe um arquivo reader a ser lido, inicializa o parser e chama o * parser para ler passo a passo o roteiro do programa. * * @param reader * @return List<Step> uma lista de de passos. * @throws TiraTeimaLanguageException * @throws ParseException */ private List<Step> parse(Reader reader) throws TiraTeimaLanguageException, ParseException { TiraTeimaParser parser = new TiraTeimaParser(reader); /** Inicializa a lista de estados e os passos a serem executados sobre a variável step */ Step step; List<Step> passos = new ArrayList<Step>(); /** Enquanto o parser ler um passo e retorná-lo */ while ((step = parser.step()) != null) { /** Imprime o passo para fins de depuração */ System.out.println(step.toString()); /** Adiciona o estado criado à lista de estados. */ passos.add(step); } return passos; } }