package tirateima.main; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.io.InputStreamReader; import java.io.Reader; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import javax.swing.JFrame; import javax.swing.JOptionPane; import tirateima.gui.Principal; import tirateima.gui.arquivos.AbstractArquivo; import tirateima.gui.editortexto.Linguagem; /** Exemplo de tag para se colocar no HTML: <applet code="br.unb.cic.algostep.main.Applet" archive="tirateima.jar" height="600" width="800"> <param name="arq_fonte" value="[nome do arquivo fonte]"> <param name="arq_texto" value="[nome do arquivo txt]"> <param name="modo" value="['janela' ou 'applet']"> </applet> */ @SuppressWarnings("serial") public class Applet extends java.applet.Applet { private static Applet instance = null; /** Um cache com as entradas que nós já vimos até agora. Salvamos * a URL do arquivo de passos como chave. */ private HashMap<URL, Principal> entradas = new HashMap<URL, Principal>(); /** Um cache de janelas (visíveis ou não). Usado apenas pelo applet. */ private HashMap<URL, Programa> janelas = null; /** * Normaliza uma URL. */ public URL normalizarURL(String url) throws MalformedURLException { if (!url.toLowerCase().startsWith("http://")) return new URL(getCodeBase() + url); else return new URL(url); } /** * Retorna uma referencia do applet, caso tenha sido iniciado nesse modo * @return */ public static Applet getInstance(){ return instance; } /** * Retorna um Reader correspondente a uma URL (relativa ou absoluta). */ public Reader getArquivo(URL url) throws Exception { return new InputStreamReader(url.openConnection().getInputStream()); } /** * Prepara em background uma entrada. Isso significa baixar todos os * arquivos e interpretá-los. */ public void prepararEntrada(String str_fonte, String str_texto) throws MalformedURLException { prepararEntrada(normalizarURL(str_fonte), normalizarURL(str_texto), null); } /** * Prepara em background uma entrada. Isso significa baixar todos os * arquivos e interpretá-los. */ private void prepararEntrada(final URL url_fonte, final URL url_texto,final Linguagem linguagem) { new Thread(new Runnable() { public void run() { Principal p; try { p = new Principal(getArquivo(url_fonte), getArquivo(url_texto),linguagem); } catch (Exception e) { e.printStackTrace(); p = null; } synchronized (entradas) { if (!entradas.containsKey(url_texto)) entradas.put(url_texto, p); entradas.notifyAll(); // se algum thread estiver esperando }; } }).start(); } /** * Retorna uma entrada que foi preparada anteriormente. Caso a preparação * em background ainda não tenha sido concluída, este método bloqueia. * * Retorna 'null' quando houver um erro na preparação da entrada. * Se a url não tiver sido preparada, ele não retorna *nunca*. */ private Principal getEntrada(URL url_texto) { while (true) { synchronized (entradas) { if (entradas.containsKey(url_texto)) return entradas.get(url_texto); else try { entradas.wait(); } catch (InterruptedException e) { e.printStackTrace(); return null; } } } } /** * Abre uma janela com uma entrada previamente preparada. * Pode ser chamado quantas vezes quantas forem desejadas após * a entrada ter sido preparada. */ public void abrirEntrada(String str_fonte, String str_texto) throws MalformedURLException { // Não usamos str_fonte mas pegamos como argumento para caso no // futuro ele seja útil nós não tenhamos que reescrever todos // os JavaScripts. if (str_fonte != str_texto) return; abrirEntrada(normalizarURL(str_texto)); } /** * Abre uma janela com uma entrada previamente preparada. */ private void abrirEntrada(final URL url_texto) { Principal principal = getEntrada(url_texto); Programa p; synchronized (janelas) { if (janelas.containsKey(url_texto)) p = janelas.get(url_texto); else { // Pegamos 'principal' fora do synchronized para // diminuir o tempo que gastamos aqui. Não faz mal // pegá-lo no outro caso acima. p = new Programa(principal); p.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); janelas.put(url_texto, p); } } p.setVisible(true); p.toFront(); } @Override public void init() { try { instance = this; AbstractArquivo.url_base = normalizarURL("").toString(); String modo = getParameter("modo").toLowerCase(); if (modo.equals("janela") || modo.equals("applet")) { //Pega a linguagem Linguagem linguagem = null; if(getParameter("arq_fonte").endsWith(".c") || getParameter("arq_fonte").endsWith(".C")) linguagem = Linguagem.C; else if(getParameter("arq_fonte").endsWith(".pas") || getParameter("arq_fonte").endsWith(".PAS")) linguagem = Linguagem.PASCAL; //Pega a url dos arquivos URL url_fonte = normalizarURL(getParameter("arq_fonte")); URL url_texto = normalizarURL(getParameter("arq_texto")); prepararEntrada(url_fonte, url_texto,linguagem); Principal principal = getEntrada(url_texto); if (principal == null) throw new Exception("Erro na preparação, veja o Console Java"); if (modo.equals("janela")) { /* Pega largura e altura da janela. * Se não existirem, usa valores padrão. */ int largura, altura; try{ String l_temp = getParameter("largura"); largura = l_temp != null ? Integer.parseInt(l_temp) : 800; String a_temp = getParameter("altura"); altura = l_temp != null ? Integer.parseInt(a_temp) : 800; }catch(NumberFormatException e){ largura = 800; altura = 600; } Programa p = new Programa(principal); p.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); p.setSize(largura, altura); p.setVisible(true); } else { GridBagConstraints gbc = new GridBagConstraints(); setLayout(new GridBagLayout()); gbc.anchor = GridBagConstraints.CENTER; gbc.fill = GridBagConstraints.BOTH; gbc.weightx = gbc.weighty = 1.0; add(principal); } } else if (modo.equals("escondido")) { // Não faz nada =). // No modo 'escondido' nós esperamos sermos chamados pra agir, // e não o contrário. Veja 'prepararEntrada(String, String)' // e 'mostrarEntrada(String, String)' (as versões que recebem // URLs desses métodos não são destinadas à interface com // código JavaScript). // Como precaução, vamos nos assegurar que não nos foi dado // nenhum arquivo direto como argumento. if (getParameter("arq_fonte") != null || getParameter("arq_texto") != null) throw new Exception("No modo \"escondido\" não devem ser" + "especificados os parâmetros \"arq_fonte\" e" + "\"arq_texto\"."); // Como mais precaução, criaremos 'janelas' aqui para que o // applet nunca seja usado como 'escondido' sem estar escondido. janelas = new HashMap<URL, Programa>(); } else { throw new Exception("Modo \"" + modo + "\" desconhecido."); } } catch(Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, e, "Tira-Teima", JOptionPane.ERROR_MESSAGE); } } }