trab final - relatório - Inf

Propaganda
Universidade Federal do Rio Grande do Sul
Instituto de Informática
Departamento de Informática Aplicada
INF01120
TÉCNICAS DE CONSTRUÇÃO DE
PROGRAMAS
RELATÓRIO DO TRABALHO
FINAL
DA DISCIPLINA
1
PROFESSOR OTACÍLIO JOSÉ CAROLLO DE
SOUZA
SEMESTRE 2007/2
TURMA C
PROJETO FINAL
CodeGear:
The JavaCode Editor
2
Realizado por:
Pietro Facchini Biasuz
Cartão:
151362
Soraya Sybele Hossain
Cartão:
124917
26 de novembro de 2007.
ÍNDICE
1. Introdução ...............................................
2. Projeto Inicial ...............................................
2.1 Escolhendo o projeto ...............................................
2.2 A idéia ...............................................
2.3 Desenvolvendo a idéia ...............................................
2.4 O projeto ...............................................
3
2.5 Escolha da linguagem
...............................................
3. Pesquisa ...............................................
3.1 Editores de texto X Editores de código ...............................................
3.2 Aplicando conhecimentos da disciplina ...............................................
4. Planejamento
4.1 Diagrama de estrututras ...............................................
4.2 Divisão das tarefas e prioridades ...............................................
4.3 Comunicação entre equipe ...............................................
5. Implementação ...............................................
5.1 Recursos disponíveis ...............................................
5.2 Detalhes da implementação ...............................................
5.3 Testes realizados em trechos fundamentais
...............................................
5.4 Dificuldades encontradas ...............................................
5.5 Comunicação ...............................................
6. Experiência Adquirida ...............................................
6.1 Se reiniciado, como seria ...............................................
6.2 O que poderia ser melhorado ...............................................
7. Considerações finais ...............................................
7.1 Sobre o CodeGear ...............................................
7.2 Sobre nosso aprendizado ...............................................
8. Anexos ..............................................................
8.1 Anexo 1 - O código-fonte do projeto ...............................................
8.2 Anexo 2 - Screenshots do programa ...............................................
9. Referências .............................................................................
1. INTRODUÇÃO
4
A criação de um software para fins acadêmicos (geralmente de maneira individual)
para atender a demanda de determinada disciplina em um curso de graduação é tarefa à
qual todo estudante está habituado. Porém o desenvolvimento em grupo de um projeto
extenso, com muitos passos de implementação, atendendo a diversos pré-requisitos não
é trivial.
Com o objetivo de familiarização com as etapas e problemas envolvidos no ciclo de
vida de um programa, foi desenvolvido pelo grupo, ao longo do semestre, um programa
para edição de textos, especialmente para a escrita de código.
Um editor de textos é um programa complexo, com diversas funcionalidades
básicas ou avançadas a serem implementadas. Ele exige uma análise detalhada de
requisitos, um processo de decisão de projeto (tanto para aspectos genéricos quanto para
detalhes de implementação), filosofia de trabalho, mecanismos de desenvolvimento
paralelo por mais de um implementador simultâneamente e de modularização e
integração de software.
É necessário também que se leve em conta, antes de começar uma etapa de
codificação, o modelo utilizado na abordagem de um problema. Quando se está
desenvolvendo em um grupo onde não se tem a visão geral do software, não basta
resolver o problema. É necessário resolver o problema de maneira que outra pessoa
possa facilmente compreender qual foi a solução abordada. Para isso, é necessário criar
esquemas e modelos para que as peculiaridades pessoais de um desenvolvedor no grupo
não acabem prejudicando o projeto e tomando mais tempo (pois no "mundo real", tempo é
sinônimo de custo).
Neste documento, nossa intenção é descrever as diversas situações em
que estivemos envolvidos no decorrer desse projeto. Iremos detalhar
as etapas, requisitos, modelos e problemas descritos acima para que se
possa ter uma melhor compreensão do projeto como um todo
(compreensão essa que não pode ser obtida apenas com a avaliação do
resultado final, isto é, do editor de texto pronto que foi "entregue ao
cliente"). Utilizaremos diversas vezes a analogia de que o programa foi
desenvolvido para um mercado consumidor ou para um cliente, uma
vez que o desenvolvimento ocorreu com o intuito de criar um software
5
competitivo e inovador, tal qual o processo de desenvolvimento que se
dá no "mundo real".
2. PROJETO INICIAL
2.1 ESCOLHENDO O PROJETO
Ao longo de semestres anteriores da disciplina Técnicas de Construção de
Programas, os projetos finais eram alternados entre editores de texto e planilhas
eletrônicas. Esses projetos ilustram bem todo o conhecimento teórico adquirido na
disciplina, pois são projetos grandes, para serem realizados em equipe e que utilizam
todas as técnicas de desenvolvimento de um software que tivemos oportunidade de
aprender.
No semestre corrente, deveria ser proposta a implementação de um editor de texto,
mas foi decidido que a escolha do tema dos projetos seriam liberados. É complicado
encontrar um tema de projeto em que possamos por em prática tudo o que aprendemos
na disciplina, ainda mais que a escolha do tema teria que ser feita no início do semestre,
quando ainda não tínhamos estudado todo o conteúdo da disciplina ainda. Como nos foi
dito pelo professor, em aula, que implementar um editor de texto seria uma ótima forma
de avaliar todo o conhecimento da disciplina, optamos por implementar uma versão
melhorada de um editor de texto comum: queríamos realizar um projeto de um editor de
texto para a escrita de código de programação.
2.2 A IDÉIA
Muitas vezes, precisamos editar pequenos trechos de código ou implementar
pequenos programas. Quando isso ocorre, recorremos a editores de código bastante
simples. Há uma grande variedade de editores de código disponíveis na Web, alguns
grátis (Freeware) e outros pagos (que geralmente são disponibilizados em uma versão
Shareware ou Trial, para que os usuários testem o software antes de realizar a compra,
caso fiquem satisfeitos com o produto). Apesar da aparente simplicidade de alguns dos
editores de código mais populares, eles, muitas vezes, apresentam um comportamento
6
inesperado, surpreendendo o usuário, prejudicando o andamento das tarefas e, por
conseqüência, tornando o trabalho simples mais demorado que o necessário, e assim
perdendo a vantagem principal da utilização de um editor de código, a velocidade de
edição. Além disso, a maior parte dos editores não apresentam algumas funcionalidades
simples que facilitariam muito a codificação.
Pensando no problema descrito, decidimos que seria de grande valia a construção
de um editor de código que conseguisse incorporar uma utilização mais intuitiva e que
possuísse funcionalidades que ajudassem o programador tanto na sintaxe da linguagem
quanto na compilação. Além disso, a escolha do projeto nos permitiria experimentar como
é o desenvolvimento de um projeto grande, comparado com o que tínhamos feito até
agora.
2.3 DESENVOLVENDO A IDÉIA
Ao início do projeto, imaginamos muitas funcionalidades inovadoras e que
facilitariam a vida dos mais variados tipos de usuários de editores de código. Chegamos a
imaginar funcionalidades inovadoras até hoje nunca implementadas nesse tipo de
software. Pensamos também em implementar muitas funcionalidades que já existem nos
editores usados atualmente, sendo essas as nossas preferidas de forma a adaptar o
editor ao nosso uso diário.
A criação de uma ferramenta que pudesse auxiliar nas tarefas básicas do dia-a-dia
foi, com certeza, prioridade. Por esse motivo, essas ferramentas foram estudadas com
mais ênfase na etapa inicial do projeto. Já as ferramentas revolucionárias foram
idealizadas e sua aplicabilidade e possibilidade de implementação foi pesquisada com
mais receio, uma vez que estávamos explorando território desconhecido.
A primeira etapa do projeto constituiu-se de uma pesquisa de mercado, em que
realizamos uma coleta de informações sobre produtos similares ao que foi projetado.
Essa coleta e posterior síntese de dados em um relatório e uma apresentação nos rendeu
muitas idéias sobre o trabalho que tínhamos pela frente. A etapa seguinte foi projetar o
programa, criando um modelo de modularização e um cronograma aproximado de
eventos para o desenvolvimento. Este projeto nos serviu de base para diversas etapas
seguintes, mas também se mostrou falho em alguns aspectos depois de algum tempo.
Por esse motivo, ele foi, por diversas vezes adaptado e modificado ao longo do tempo.
7
Pagamos caro pela nossa ousadia. Pensar grande demais nos fez perder muito
tempo com pequenos detalhes irrelevantes ao trabalho. Apesar disso, conseguimos,
depois de perceber o tamanho do tempo perdido, implementar o que nos era pedido de
forma clara e simples desde o início deste semestre.
2.4 O PROJETO
Aqui citamos as features que gostaríamos de implementar em nosso editor de
código. Algumas não chegaram a ser implementadas pela falta de planejamento, como
citamos acima, já que não estávamos habituados a trabalhar com grandes projetos. Mas
elas ficam como sugestão para uma futura melhora do programa.
O nosso editor de código, que aqui já teria até um nome: CodeGear, herda muitas
funcionalidades de um editor de texto comum, como segue:

Criar novo arquivo;

Ações de abrir, editar e salvar arquivos existentes;

Ações de copiar, colar e recortar;

Possibilidade de desfazer e refazer as últimas alterações realizadas;

Busca de um sub-texto dentro do texto corrente.
Abdicamos das funcionalidades de escolha de fonte, tamanho e cor, pois isso seria
desnecessário na escrita de um código.
Como uma funcionalidade extra, pensamos em implementar a utilização de abas
para possibilitar a edição de diversos códigos na mesma janela do programa.
Além disso, existem as funcionalidades extras específicas que caracterizam um
editor de código e auxiliam na codificação de um programa. Entre elas:

Realçar os tokens (palavras reservadas) da linguagem específica em que o
usuário está programando;

Salvar o trabalho automaticamente a um período de tempo pré-determinado, em
arquivos separados, caso o usuário desejar voltar para um estado anterior da
codificação;

Localizador de identificadores que indiquem abertura e fechamento de um
8
bloco de programa, por exemplo, as {} (chaves) das linguagens C e Java. Quando
o usuário selecionasse um dos identificadores, o programa se encarregaria de
achar o identificador correspondente, seja de abertura ou fechamento do bloco de
código.
Também pensamos em algumas opções diferenciais que não são normalmente
em encontradas nos editores de código, em geral:
 Disponibilizar, no momento em que o usuário digita o código, ajuda sobre o uso de
cada Token, por exemplo: no caso do usuário estar programando em Java, ao digitar
'for ', o programa reconheceria o Token e preencheria for com (;;) e apareceria uma
caixa de texto informando o que cada parâmetro a ser digitado significa;
 Ter a possibilidade de compilar o código ativo diretamente do editor, utilizando
um compilador de linha de comando DOS, como por exemplo, o JDK, no caso de
Java.
2.5 ESCOLHA DA LINGUAGEM
Para a implementação do editor de código, optamos por utilizar a linguagem de
programação Java[1], mais especificamente, a versão J2SE, por ser uma linguagem
orientada a objetos, com a qual poderíamos utilizar esse recurso para o reaproveitamento
de determinadas partes do código, como nos foi ensinado em aula, além de ser uma
linguagem multi-plataforma, tendo em vista que, em geral, programadores utilizam
variados sistemas operacionais e não se restringem a um único, como no caso de um
usuário comum. Outro fator decisivo na escolha da linguagem, foi o aprendizado de uma
nova linguagem que teríamos ao desenvolver o programa, visto que não tínhamos
trabalhado com essa linguagem ainda e seria uma boa oportunidade de conhecê-la.
Sobre as questões técnicas da linguagem, utilizaremos a biblioteca Strings que
facilitará o trabalho em relação a manipulação de strings, para podermos identificar os
Tokens (palavras reservadas), localizar as variáveis e os identificadores de abertura e
término de um bloco de programa.
9
Para criação da interface, foi escolhida a biblioteca Swing, pois é uma biblioteca
bastante completa para trabalhar com interfaces e ela ajudará na construção dos botões e
menus, e também na própria área de digitação do código.
Para compilar o código diretamente do editor, será necessária a construção de um
arquivo em lotes que deverá ser executado no momento em que se deseja realizar a
compilação. Será necessária a instalação separadamente do JDK (Java Development Kit)
no computador do usuário para realizar essa tarefa.
A parte de ajuda ao usuário, a parte de localização de variáveis e também a parte
da compilação diretamente do editor são especificas para cada linguagem. Já as demais
partes são universais, ou seja, funcionariam independentemente da linguagem, sem
necessidade de adaptações especiais para cada linguagem. Inicialmente, o editor de
código será voltado para a linguagem Java.
3. PESQUISA
3.1 EDITORES DE TEXTO x EDITORES DE CÓDIGO
Primeiramente, antes de começarmos a implementação do projeto, tínhamos que
pesquisar sobre ferramentas já existentes, para assim poder realizar o planejamento de
nosso trabalho.
Começamos pesquisando sobre editores de texto básicos, afinal, essa seria a base
para o nosso software. Ao buscar a definição de editores de texto, encontramos o
seguinte:
“Um editor de texto é um tipo de programa utilizado para a edição de arquivos de
texto plenos.
Editores de texto são geralmente disponibilizados juntamente com Sistemas
Operacionais, ou pacotes de desenvolvimento, e podem ser usados para modificar
documentos, arquivos de configuração e código-fonte de programação.”[2]
10
Figura 1: exemplo de um famoso editor de código: o Vim. Conhecido pela suas inúmeras funcionalidades,
mas também pela sua grande dificuldade de utilização.
Existem importantes diferenças entre arquivos de texto plenos criados por um
editor de texto, e documentos criados por processadores de texto, tais como Microsoft
Word, WordPerfect ou OpenOffice. Basicamente:

Um arquivo de texto pleno é representado e editado ao mostrar todos os caracteres
que estão presentes no arquivo. Os únicos caracteres utilizados para marcação
são os caracteres de controle no conjunto de caracteres utilizados. Em prática, isso
inclui “nova linha” (CR+LF) e “tab”. O conjunto de caracteres mais comumente
11
utilizado é o ASCII (American Standard Code for Information Interchange). Arquivos
de texto plano são mais utilizados para programação e configuração, e menos
freqüentemente utilizados para documentação, como eram antigamente.

Documentos criados por um processador de texto geralmente contém caracteres
de controle específicos do seu tipo de arquivo, diferente do que é definido no
conjunto de caracteres. Isso permite funções tais como negrito, itálico, fontes,
colunas, tabelas, etc.

Processadores de texto podem normalmente editar arquivos de texto plenos e
salvá-los nesse mesmo formato. Mas precisamos ter cuidado em dizer para o
programa que é isso que queremos. Isso é especialmente importante em casos
como código-fonte, HTML e arquivos de configuração e controle. Senão o arquivo
conterá esses “caracteres especiais” únicos de tipos de arquivo de processadores
de texto e não serão tratados corretamente na utilidade para a qual os arquivos
foram destinados.
Pelos motivos citados anteriormente, vimos que a melhor maneira de implementar
um editor de código, seria tendo um editor de texto pleno como base. Assim,
consideramos o que foi descrito da sessão 2.4, e decidimos não utilizar opções de
formatação de texto, pois isso poderia prejudicar o usuário na hora de escrever o código
no editor, e trazer conseqüências indesejáveis.
3.2 APLICANDO CONHECIMENTOS DA DISCIPLINA
Como o objetivo do trabalho final era exatamente mostrar o que foi aprendido na
disciplina, e a sua aplicação no desenvolvimento de um aplicativo de grande porte,
também pesquisamos exaustivamente a bibliografia da disciplina, assim como o conteúdo
dado em aula. Depois dessa pesquisa, onde já tínhamos conseguido reunir um bom
conhecimento do que íriamos utilizar, resolvemos começar o planejamento do projeto.
4. PLANEJAMENTO
4.1 DIAGRAMA DE ESTRUTURAS
12
Figura 2: Diagrama de estruturas do CodeGear
4.2 DIVISÃO DAS TAREFAS E PRIORIDADES
Antes de começarmos a implementar o editor, teríamos que dividir algumas tarefas,
pois não tínhamos muita disponibilidade de encontros presenciais, e a nossa
comunicação durante as etapas do desenvolvimento teria que ser feita de forma virtual.
Estabelecemos prioridades durante a divisão das tarefas, pois primeiramente
teríamos que construir uma base para o nosso editor de código, que seria o editor de
texto pleno, para depois nos preocuparmos com as funcionalidades de um editor de
código em si. Segue o esquemático do que ficou definido:
13
1ª apresentação
Prioridades
Implementação do editor de texto pleno.
Implementação da interface básica do

Pietro
editor;
Ações de copiar, colar e recortar um
determinado trecho de texto.
2ª apresentação
Implementação do editor de código, com
base no editor de texto pleno.
Realçar os tokens (palavras reservadas) no
texto corrente;
Criar mecanismo de salvamento automático
do arquivo dentro de um tempo estipulado
pelo usuário.
Implementação da inferface básica do Implementação da interface completa do

Soraya
editor;
editor;
Manipulações sobre arquivos: criar novo Criar um mecanismo de abas para cada novo
arquivo, abrir arquivo, salvar arquivo.
arquivo;
Extras

Pietro
Possibilidade de desfazer e refazer as
últimas alterações realizadas no arquivo
Ajuda sobre o uso de cada token;
Maneira de integrar o editor de código com
um compilador.
Localizador de identificadores de abertura e

Soraya
Criar um mecanismo de busca de um fechamento de um bloco de código;
sub-texto dentro do texto corrente
Maneira de integrar o editor de código com
um compilador.
Tabela 1: divisão das tarefas do projeto
4.3 COMUNICAÇÃO ENTRE EQUIPE
A comunicação entre os membros da equipe de desenvolvimento foi
realizada, na maioria das vezes, de forma virtual. Em sessões
posteriores serão mostrados exemplos de conversa entre a equipe.
5. IMPLEMENTAÇÃO
5.1 RECURSOS DISPONÍVEIS
Ao escolhermos uma linguagem orientada a objetos na implementação do nosso
14
editor, pensamos em quão útil seria a característica de reuso de código, típica das
linguagens OO.
O ambiente escolhido para o desenvolvimento foi o NetBeans[4], que se mostrou
uma ferramenta bastante poderosa na implementação do programa, e também de fácil
uso. O NetBeans é um IDE Java desenvolvido pela empresa Sun Microsystems, a mesma
que desenvolve a linguagem Java. Ele é um ambiente de desenvolvimento integrado
gratuito e de código aberto para desenvolvedores de software. O IDE é executado em
muitas plataformas, como Windows, Linux, Solaris e MacOS. É fácil de instalar e usar. O
NetBeans IDE oferece aos desenvolvedores todas as ferramentas necessárias para criar
aplicativos profissionais de desktop, empresariais, Web e móveis multiplataformas. Nós
utilizamos a versão 5.5.1 em nosso projeto.
5.2 DETALHES DA IMPLEMENTAÇÃO
Em um trabalho como o nosso, a descrição de detalhes de implementação pode
ser bastante maçante. Por esse motivo, daremos aqui uma breve noção sobre o código
do editor. Mais detalhes podem ser encontrados nos anexos ou então nos comentários
em código.
A interface gráfica foi construída utilizando a API Swing, que é amplamente
utilizada por quase todas as aplicações Java que requerem um layout de interação com o
usuário. Foram criados botões e seus comportamentos; um painel de Scrool para permitir
a rolagem do texto e uma área de texto, propriamente dita, onde se digita o código.
Para o reconhecimento das palavras reservadas da linguagem, foi construído um
vetor com algumas palavras e complementos. A partir daí, o programa, em tempo real,
reconhece as palavras reservadas, sugere seus finais e as destaca do restante do código.
O destaque das palavras é feito com a utilização de Highlights. Ao reconhecer uma
palavra da linguagem, o programa pinta o fundo ao redor da palavra. Foram utilizados
Highlights diferentes para cada função: azul para achar as chaves, vermelho para
palavras procuradas e cinza para palavras reservadas.
As funções de achar a outra chave correspondente e a função de Salvar
automático foram feitas utilizando Timers. A um dado intervalo de tempo, as tarefas
programadas são executadas e seus resultados (arquivo gerado e Highlights) são
gerados. Para essa tarefa não interromper a execução do programa principal foram
15
utilizadas Threads.
5.3 TESTES REALIZADOS EM TRECHOS FUNDAMENTAIS
Houve uma grande quantidade de testes realizados, desde o início a partir da
implementação da interface até a parte da lógica utilizada pelo programa para o
reconhecimento das palavras.
Um recurso de teste bastante utilizado foi o breakpoint. Além desse, o programa
apresentar seus resultados passo-a-passo também foi muito utilizado principalmente na
parte da programação lógica.
Sem dúvida, a parte de implementação que mais necessitou testes, tanto para
verificar se a lógica empregada estava correta e, também para entender o que cada
função utilizada realizava de fato, foi a parte da implementação do reconhecimento e
procura das palavras reservadas.
5.4 DIFICULDADES ENCONTRADAS
Houve muitas dificuldades para duas pessoas, que ainda não se conheciam,
trabalhar em uma mesma implementação. A comunicação e a definição de como as
partes de cada um deviam interagir foi essencial para o sucesso do trabalho.
A maior dificuldade encontrada foi a disponibilidade de tempo e organização do
projeto. No início da implementação, tudo foi feito calmamente e de forma "experimental",
pois tínhamos a idéia de que havia ainda muito tempo disponível para fazer a
programação. Conforme o prazo final se aproximou, o ritmo de trabalho teve que ser
revisado, com o aumento da produtividade e com menos tempo para projetar e repensar
maneiras mais eficientes de implementação. Outra grande dificuldade foi a divisão de
tarefas entre os membros do grupo, pois até o momento tínhamos o hábito de programar
sozinhos e ter uma noção global do programa.
16
5.5 COMUNICAÇÃO
Desde o início do trabalho, armazenamos nossas conversas por e-mail com a
intenção de não perdermos boas idéias durante a implementação de nosso editor. Houve
além da troca de e-mails, longas conversas por I.M. que fizeram muita diferença nas
decisões tomadas diante de como fazer o editor.
Abaixo seguem algumas conversas por e-mail, e no fim delas uma das conversas
por IM citadas acima:
<completar, ou retirar – não esquecer do índice>
6. EXPERIÊNCIA ADQUIRIDA
6.1 SE REINICIADO, COMO SERIA
Se reiniciássemos o programa hoje, a principal diferença seria na organização
inicial com um melhor planejamento das tarefas a serem realizadas. Também
organizaríamos melhor o tempo, e a divisão de tarefas seria mais bem distribuída, de
maneira mais "encapsulada", onde cada integrante do grupo teria tarefas bem definidas e
pensadas antes da implementação o que diminuiria dependência de dados. Havendo
tempo, poderíamos implementar várias coisas que tínhamos em mente, mas que não
foram possíveis.
6.1 O QUE PODERIA SER MELHORADO
Se desde o início planejássemos nosso tempo de forma a compreender o tempo
necessário para o correto funcionamento do que teríamos de implementar de mais básico,
talvez pudéssemos ter ido mais longe na implementação dos extras que planejávamos.
17
7. CONSIDERAÇÕES FINAIS
7.1 SOBRE O CODEGEAR
Atingimos nosso objetivo na criação de um editor genérico e fácil de usar. Foram
implementadas várias funcionalidades que havíamos visado no projeto inicial do editor de
código. Além de ter contribuído para o enriquecimento do aprendizado na disciplina, pois
pudemos por em prática os conhecimentos adquiridos.
No Anexo 2 – Screenshots do programa é possível ter uma idéia do resultado,
através das capturas de tela exibidas. Elas mostram como a interface ficou simples,
porém amigável, exatamente o pretendido. Também mostramos as funcionalidades
implementadas e o que foi alcançado do que foi pretendido.
7.2 SOBRE NOSSO APRENDIZADO
A disciplina de Técnicas de Construção de Programas, por fim, se
mostrou uma das disciplinas mais importantes do curso, pois nela é
possível colocar (ou ao menos tentar) em prática tudo o que
aprendemos até o momento e ainda ter vontade de aprender mais para
poder aperfeiçoar a nossa futura produção de software.
8. ANEXOS
8.1 ANEXO 1 – O CÓDIGO-FONTE DO PROJETO
import java.awt.Event;
import java.awt.FileDialog;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
18
import java.text.SimpleDateFormat;
import javax.swing.*;
import java.util.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.event.ActionEvent;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.GroupLayout.*;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Document;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.swing.text.StyledDocument;
import javax.swing.undo.*;
import java.awt.Color;
import java.io.*;
public class CodeGear extends JFrame
implements DocumentListener {
private JLabel jLabel1;
private JScrollPane jScrollPane1;
private JTextArea textArea; JTextPane textPane; AbstractDocument doc;
private JMenuBar menuBar;
private JMenu buttonMenu, buttonEdit, buttonOpcoes, buttonSearch;
private JMenuItem btnOpen, btnClose, btnSave, btnSaveAs, btnAuto, btnCopy, btnPaste, btnCut,
btnSelAll, btnFind, btnUnfind;
private JTextField textFinder;
private JSpinner winSave;
private JFrame frame;
private JRadioButtonMenuItem tempo3, tempo5, tempo10, tempo15, tempoOff;
private JTextField entry;
private static final String COMMIT_ACTION = "commit";
private static final String SPACE_ACTION = "space";
private static enum Mode { INSERT, COMPLETION };
private final List<String> words;
private final List<String> plus;
private final int cursor [];
private Mode mode = Mode.INSERT;
private int posVet, posIni=0;
private String saveStr = null;
private int lastSpc = 0;
private String filename;
private boolean firstSave = true;
private String strCopy = "";
19
public java.util.Timer tSave, tChaves;
private Object[] options = {"Salvar","Descartar","Cancelar"};
public String buf = "";
public String palavra="";
public Highlighter.HighlightPainter PainterGray = new MyHighlightPainter(Color.LIGHT_GRAY);
public Highlighter.HighlightPainter PainterRed = new MyHighlightPainter(Color.RED);
public Highlighter.HighlightPainter PainterBlue = new MyHighlightPainter(Color.BLUE);
protected UndoAction undoAction;
protected RedoAction redoAction;
protected UndoManager undo = new UndoManager();
public CodeGear() {
super("CodeGear - The JavaCodeEditor");
initComponents();
textArea.getDocument().addDocumentListener(this);
textArea.getDocument().addUndoableEditListener(new MyUndoableEditListener());
InputMap im = textArea.getInputMap();
ActionMap am = textArea.getActionMap();
im.put(KeyStroke.getKeyStroke("ENTER"), COMMIT_ACTION);
am.put(COMMIT_ACTION, new CommitAction());
im.put(KeyStroke.getKeyStroke("SPACE"), SPACE_ACTION);
am.put(SPACE_ACTION, new SpaceAction());
//cria um banco de dados com algumas palavras reservadas da linguagem Java (Tokens)
words = new ArrayList<String>();
plus = new ArrayList<String>();
cursor = new int[30];
words.add("ArrayList");
plus.add("ArrayList<TYPE>(SIZE) ");
cursor[0]=10;
words.add("Boolean");
plus.add("Boolean
");
plus.add("class
");
plus.add("enum
");
plus.add("extends
");
plus.add("false
");
plus.add("final
");
cursor[1]=8;
words.add("class");
cursor[2]=13;
words.add("enum");
cursor[3]=5;
words.add("extends");
cursor[4]=8;
words.add("false");
cursor[5]=6;
words.add("final");
cursor[6]=6;
words.add("for");
plus.add("for (IND=0;IND >0;IND--)");
cursor[7]=5;
words.add("if");
plus.add("if () {\n
\n} else {\n
20
\n} ");
cursor[8]=4;
words.add("import");
plus.add("import
");
plus.add("int
");
plus.add("new
");
plus.add("null
");
plus.add("package
");
plus.add("private
");
cursor[9]=7;
words.add("int");
cursor[10]=4;
words.add("new");
cursor[11]=4;
words.add("null");
cursor[12]=4;
words.add("package");
cursor[13]=8;
words.add("private");
cursor[14]=8;
words.add("psvm");
{\n
\n} ");
plus.add("public static void main(String args[])
cursor[15]=52;
words.add("public");
plus.add("public
");
cursor[16]=7;
words.add("sout");
plus.add("System.out.println(\"\"); ");
cursor[17]=20;
words.add("string");
plus.add("String
");
plus.add("super
");
cursor[18]=7;
words.add("super");
cursor[19]=6;
words.add("switch");
plus.add("switch
()
");
plus.add("this
");
cursor[20]=9;
words.add("this");
cursor[21]=5;
words.add("try");
plus.add("try {\n
\n} catch (EXCEPTION e)
{\n e.printStackTrace(); \n} ");cursor[22]=13;
words.add("void");
plus.add("void
");
cursor[23]=5;
words.add("while");
plus.add("while
()
");
cursor[24]=7;
words.add("else");
plus.add("else ");
}
//cria a interface gráfica do programa
private void initComponents() {
textArea = new JTextArea();
textPane = new JTextPane();
textPane.setCaretPosition(0);
textPane.setMargin(new Insets(5,5,5,5));
StyledDocument styledDoc = textPane.getStyledDocument();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jScrollPane1 = new JScrollPane(textArea);
tSave = new java.util.Timer();
21
tSave.schedule(new autoSave(),300000,300000);
tChaves = new java.util.Timer();
tChaves.schedule(new acharOutro(),500,500);
addButtons();
addListenersButtons();
GroupLayout layout = new GroupLayout(getContentPane());
getContentPane().setLayout(layout);
ParallelGroup hGroup = layout.createParallelGroup(GroupLayout.Alignment.LEADING);
SequentialGroup h1 = layout.createSequentialGroup();
ParallelGroup h2 = layout.createParallelGroup(GroupLayout.Alignment.TRAILING);
h2.addComponent(jScrollPane1, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 212,
Short.MAX_VALUE);
h1.addContainerGap();
h1.addGroup(h2);
h1.addContainerGap();
hGroup.addGroup(Alignment.TRAILING,h1);
layout.setHorizontalGroup(hGroup);
ParallelGroup vGroup = layout.createParallelGroup(GroupLayout.Alignment.LEADING);
SequentialGroup v1 = layout.createSequentialGroup();
v1.addContainerGap();
v1.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED);
v1.addComponent(jScrollPane1, GroupLayout.DEFAULT_SIZE, 100, Short.MAX_VALUE);
v1.addContainerGap();
vGroup.addGroup(v1);
layout.setVerticalGroup(vGroup);
pack();
}
//cria e adiciona os botões à interface gráfica
private void addButtons() {
22
menuBar = new javax.swing.JMenuBar();
buttonMenu = new javax.swing.JMenu();
buttonEdit = new javax.swing.JMenu();
buttonOpcoes = new javax.swing.JMenu();
buttonSearch = new javax.swing.JMenu();
btnOpen = new javax.swing.JMenuItem();
btnClose = new javax.swing.JMenuItem();
btnSave = new javax.swing.JMenuItem();
btnSaveAs = new javax.swing.JMenuItem();
btnCopy = new javax.swing.JMenuItem();
btnPaste = new javax.swing.JMenuItem();
btnCut = new javax.swing.JMenuItem();
btnSelAll = new javax.swing.JMenuItem();
btnFind = new javax.swing.JMenuItem();
btnUnfind = new javax.swing.JMenuItem();
undoAction = new UndoAction();
buttonEdit.add(undoAction);
redoAction = new RedoAction();
buttonEdit.add(redoAction);
buttonMenu.setText("Arquivo");
buttonEdit.setText("Editar");
buttonOpcoes.setText("AutoSave");
buttonSearch.setText("Buscar");
btnOpen.setText("Abrir");
btnClose.setText("Fechar");
btnSave.setText("Salvar");
btnSaveAs.setText("Salvar Como");
btnCopy.setText("Copiar");
btnPaste.setText("Colar");
btnCut.setText("Recortar");
btnSelAll.setText("Selecionar Tudo");
btnFind.setText("Marcar");
btnUnfind.setText("Desmarcar");
menuBar.add(buttonMenu);
menuBar.add(buttonEdit);
menuBar.add(buttonOpcoes);
menuBar.add(buttonSearch);
buttonMenu.add(btnOpen);
buttonMenu.add(btnClose);
buttonMenu.add(btnSave);
23
buttonMenu.add(btnSaveAs);
buttonEdit.add(btnSelAll);
buttonEdit.add(btnCut);
buttonEdit.add(btnCopy);
buttonEdit.add(btnPaste);
buttonSearch.add(btnFind);
buttonSearch.add(btnUnfind);
ButtonGroup group = new ButtonGroup();
tempoOff = new JRadioButtonMenuItem("OFF");
tempo3 = new JRadioButtonMenuItem("3 Minutos");
tempo5 = new JRadioButtonMenuItem("5 Minutos");
tempo10 = new JRadioButtonMenuItem("10 Minutos");
tempo15 = new JRadioButtonMenuItem("15 Minutos");
group.add(tempoOff);
group.add(tempo3);
group.add(tempo5);
tempo5.setSelected(true);
group.add(tempo10);
group.add(tempo15);
buttonOpcoes.add(tempoOff);
buttonOpcoes.add(tempo3);
buttonOpcoes.add(tempo5);
buttonOpcoes.add(tempo10);
buttonOpcoes.add(tempo15);
setJMenuBar(menuBar);
}
//*********************FUNÇÕES DE MENU**************************************
//implementação da função salvar; salva o texto digitado na janela
public void saveFunction() {
if (firstSave)
saveAsFunction();
else {
BufferedWriter out;
String text = textArea.getText();
try {
String filenameDatado = putDate(filename);
out = new BufferedWriter(new FileWriter(filenameDatado));
out.write(text);
out.close();
}
24
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
//implementação da função salvar como
public void saveAsFunction(){
JFileChooser fc = new JFileChooser();
int answ = fc.showSaveDialog(null);
if (answ == JFileChooser.APPROVE_OPTION) {
if (fc.getSelectedFile().exists()) {
//arquivo jah existe,
abre caixa
int n = JOptionPane.showConfirmDialog(
frame, "Arquivo já existe! Subescrever esse arquivo?",
"Confirmação",
JOptionPane.YES_NO_OPTION);
if (n == JOptionPane.YES_OPTION) {
if (fc.getSelectedFile().toString().endsWith(".java"))
filename = fc.getSelectedFile().toString();
else
filename = fc.getSelectedFile().toString()+ ".java";
}
else filename ="default.java";
}
else filename = fc.getSelectedFile().toString()+ ".java";
BufferedWriter out;
String text = textArea.getText();
try {
out = new BufferedWriter(new FileWriter(filename));
out.write(text);
out.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
firstSave = false;
}
else {};
}
//insere no final do nome do arquivo a data formata para a função de salvar autmomático
public String putDate(String str) {
String formato = " (MMM dd, HH mm ss)";
25
SimpleDateFormat formatter = new SimpleDateFormat(formato);
Date agora = new Date();
String data = formatter.format(agora);
data += ".java";
int corte = str.length()-5;
String strIni = str.substring(0,corte);
str = strIni + data;
return str;
}
//cria um timer para realizar o salvar automático
class autoSave extends TimerTask {
public void run() {
saveFunction();
}
};
//função para achar as palavras no código; funciona como um localizar
public void find() {
String pattern=(String)JOptionPane.showInputDialog(frame,
"",
"Localizar",
JOptionPane.PLAIN_MESSAGE,
null,
null,
"");
if (pattern!=null)
highlightFinder(textArea, pattern);
}
//*********************LISTENERS**************************************
//adiciona os comportamentos aos botões
private void addListenersButtons() {
btnOpen.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new JFileChooser();
int answ = fc.showOpenDialog(null);
if (answ == JFileChooser.APPROVE_OPTION) {
File arch = fc.getSelectedFile();
textArea.setText("");
fc.removeAll();
if (fc.getSelectedFile().toString().endsWith(".java"))
filename = fc.getSelectedFile().toString();
else
filename = fc.getSelectedFile().toString()+ ".java";
26
try {
BufferedReader in = new BufferedReader(new FileReader(arch));
String str, text = "";
while ((str = in.readLine())!= null) {
text += str;
text += "\n";
}
textArea.setText(text);
vasculharTexto();
in.close();
firstSave = false;
}
catch (IOException ioe){
System.out.println("fuck");
}
}
}
});
btnSaveAs.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
saveAsFunction();
}
});
btnClose.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int n = JOptionPane.showOptionDialog
(frame,
"O que você deseja fazer com o código atual?",
"Aviso",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[2]);
if (n == JOptionPane.YES_OPTION) {
saveFunction();
textArea.setText("");
filename=null;
firstSave = true;
tSave.cancel();
}
else if (n == JOptionPane.NO_OPTION) {
textArea.setText("");
filename=null;
firstSave = true;
27
tSave.cancel();
}
else if (n == JOptionPane.CANCEL_OPTION) {
}
else {
System.out.println("t decide");
}
}
});
btnSave.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
saveFunction();
}
});
tempoOff.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
tSave.cancel();
}
});
tempo3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
tSave.cancel();
tSave = new java.util.Timer();
tSave.schedule(new autoSave(),180000,180000);
}
});
tempo5.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
tSave.cancel();
tSave = new java.util.Timer();
tSave.schedule(new autoSave(),300000,300000);
}
});
tempo10.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
tSave.cancel();
tSave = new java.util.Timer();
tSave.schedule(new autoSave(),600000,600000);
}
});
tempo15.addActionListener(new ActionListener() {
28
public void actionPerformed(ActionEvent e) {
tSave.cancel();
tSave = new java.util.Timer();
tSave.schedule(new autoSave(),900000,900000);
}
});
btnCopy.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textArea.copy();
}
});
btnPaste.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textArea.paste();
vasculharTexto();
}
});
btnCut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textArea.cut();
}
});
btnSelAll.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textArea.selectAll();
}
});
btnFind.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
find();
}
});
btnUnfind.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
removeHighlights(textArea,PainterRed);
}
});
}
//adiciona os comportamentos ao documento
public void changedUpdate(DocumentEvent ev) {
}
29
public void removeUpdate(DocumentEvent ev) {
vasculharTexto();
retiraChaves();
}
public void insertUpdate(DocumentEvent ev) {
vasculharTexto();
retiraChaves();
if (ev.getLength() != 1) {
return;
}
int pos = ev.getOffset();
String content = null;
try {
content = textArea.getText(0, pos+1);
} catch (BadLocationException e) {
e.printStackTrace();
}
// encontra onde a palavra começa
int w;
for (w = pos; w >= 0; w--) {
if (! Character.isLetter(content.charAt(w))) {
break;
}
}
if (pos - w < 2) {
//só começa a reconhecer a partir de 2 caracteres
return;
}
String prefix = content.substring(w + 1).toLowerCase();
int n = Collections.binarySearch(words, prefix);
if ((pos - w) == 2)
posVet = -n;
if (n < 0 && -n <= words.size()) {
String match = words.get(-n - 1);
if (match.startsWith(prefix)) {
String completion = match.substring(pos - w); //encontrou complemento
//complementar a tarefa depois
SwingUtilities.invokeLater(
new CompletionTask(completion, pos + 1));
30
}
} else {
// não achou nada
mode = Mode.INSERT;
}
}
private class CompletionTask implements Runnable {
String completion;
int position;
CompletionTask(String completion, int position) {
this.completion = completion;
this.position = position;
}
public void run() {
textArea.insert(completion, position);
textArea.setCaretPosition(position + completion.length());
textArea.moveCaretPosition(position);
mode = Mode.COMPLETION;
}
}
private class CommitAction extends AbstractAction {
public void actionPerformed(ActionEvent ev) {
if (mode == Mode.COMPLETION) {
int endPos = textArea.getSelectionEnd();
String buf = words.get(posVet-1);
String plusBuf = plus.get(posVet-1);
int sizeWord = buf.length() - 1;
int iniPos = endPos-sizeWord-1;
textArea.select(iniPos,endPos);
textArea.cut();
textArea.insert(plusBuf, iniPos);
textArea.setCaretPosition(cursor[posVet-1]+iniPos);
31
lastSpc = textArea.getCaretPosition();
mode = Mode.INSERT;
} else {
int lugar = textArea.getCaretPosition();
textArea.insert(" ",lugar);
textArea.replaceSelection("\n");
}
}
}
private class SpaceAction extends AbstractAction {
public void actionPerformed(ActionEvent ev) {
}
}
//**********************FUNÇÕES DE REDO E UNDO**********************************
//funções de desfazer e refazer
class RedoAction extends AbstractAction {
public RedoAction() {
super("Redo");
setEnabled(false);
}
public void actionPerformed(ActionEvent e) {
try {
undo.redo();
} catch (CannotRedoException ex) {
System.out.println("Unable to redo: " + ex);
ex.printStackTrace();
}
updateRedoState();
undoAction.updateUndoState();
}
protected void updateRedoState() {
if (undo.canRedo()) {
setEnabled(true);
putValue(Action.NAME, undo.getRedoPresentationName());
} else {
setEnabled(false);
putValue(Action.NAME, "Redo");
}
}
}
protected class MyUndoableEditListener implements UndoableEditListener {
public void undoableEditHappened(UndoableEditEvent e) {
32
undo.addEdit(e.getEdit());
undoAction.updateUndoState();
redoAction.updateRedoState();
}
}
class UndoAction extends AbstractAction {
public UndoAction() {
super("Undo");
setEnabled(false);
}
public void actionPerformed(ActionEvent e) {
try {
undo.undo();
} catch (CannotUndoException ex) {
System.out.println("Unable to undo: " + ex);
ex.printStackTrace();
}
updateUndoState();
redoAction.updateRedoState();
}
protected void updateUndoState() {
if (undo.canUndo()) {
setEnabled(true);
putValue(Action.NAME, undo.getUndoPresentationName());
} else {
setEnabled(false);
putValue(Action.NAME, "Undo");
}
}
}
//***********************FUNÇÕES DE HIGHLIGHTS*********************************
//funções de destaque (highlight) no texto
class MyHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter {
public MyHighlightPainter(Color color) {
super(color);
}
}
//se
o
cursor
estiver
posicionado
após
uma
chave,
encontra
a
respectiva
chave
do
mesmo,
destacando-a
class acharOutro extends TimerTask {
public void run() {
Highlighter hilite = textArea.getHighlighter();
33
retiraChaves();
int posCar = textArea.getCaretPosition();
int posAchou = 0;
String s="";
int ne=2;
int chaves=0;
int nd=1;
if (posCar != 0) {
try {
s = textArea.getText(posCar-1, 1);
}
catch (BadLocationException ex) {
ex.printStackTrace();
}
}
if (s.equals("}")) {
chaves++;
String text = textArea.getText();
while ((posCar-ne>=0) && (chaves>0)) {
String w = text.substring(posCar-ne,posCar-ne+1);
if (w.equals("}"))
chaves++;
if (w.equals("{")){
chaves--;
}
ne++;
}
if (chaves==0) {
posAchou = posCar-ne+1;
try {
hilite.addHighlight(posAchou, posAchou+1, PainterBlue);
} catch (BadLocationException ex) {
ex.printStackTrace();
}
}
}
if (s.equals("{")) {
chaves++;
String text = textArea.getText();
while (((nd+posCar)<text.length()) && (chaves>0)) {
String w = text.substring(posCar+nd,posCar+nd+1);
34
if (w.equals("{"))
chaves++;
if (w.equals("}")){
chaves--;
}
nd++;
}
if (chaves==0) {
posAchou = posCar+nd;
try {
hilite.addHighlight(posAchou-1, posAchou, PainterBlue);
} catch (BadLocationException ex) {
ex.printStackTrace();
}
}
}
}
}
//retira o destaque das chaves
public void retiraChaves () {
removeHighlights(textArea, PainterBlue);
}
//vasculha o texto em busca de palavras reservadas
public void vasculharTexto() {
try {
Highlighter hilite = textArea.getHighlighter();
String text = textArea.getText();
int n;
String s=" ";
for (n=0; n < text.length();n++) {
if (text.charAt(n) != s.charAt(0)) // != espaço
{
buf += text.charAt(n);
}
else {
buf = buf.trim();
//realiza uma busca no vetor words pela palavra buf
int marc = Collections.binarySearch(words, buf);
if (marc>=0) {//achou
int posF = n;
int posI = posF - buf.length();
hilite.addHighlight(posI,posF,PainterGray);
}
35
buf="";
}
}
}
catch (BadLocationException e) {
}
}
//procura a palavra pattern no texto textArea
public void highlightFinder(JTextComponent textArea, String pattern) {
removeHighlights(textArea,PainterRed);
Boolean achou = false;
try {
Highlighter hilite = textArea.getHighlighter();
Document doc = textArea.getDocument();
String text = doc.getText(0, doc.getLength());
int pos = 0;
while ((pos = text.indexOf(pattern, pos)) >= 0) {
hilite.addHighlight(pos, pos+pattern.length(), PainterRed);
pos += pattern.length();
achou = true;
}
}
catch (BadLocationException e) {
}
if (!(achou))
JOptionPane.showMessageDialog(frame,"Palavra não encontrada!");
}
//remove os destaque do tipo Painter no texto textArea
public void removeHighlights(JTextComponent textArea, Highlighter.HighlightPainter Painter) {
Highlighter hilite = textArea.getHighlighter();
Highlighter.Highlight[] hilites = hilite.getHighlights();
for (int i=0; i<hilites.length; i++) {
if (hilites[i].getPainter()== Painter) {
hilite.removeHighlight(hilites[i]);
}
}
}
//******************************************************************************
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
UIManager.put("swing.boldMetal", Boolean.FALSE);
36
new CodeGear().setVisible(true);
}
});
}
}
8.2 ANEXO 2 – SCREENSHOTS DO PROGRAMA
Aqui serão mostradas diversas screenshots do CodeGear, indicando as suas
funcionalidades.
9. REFERÊNCIAS
[1] http://java.sun.com/
[2] http://en.wikipedia.org/wiki/Text_editor
[3] http://www.javafree.org/wiki/Java
[4] http://www.netbeans.org/
[5] http://www.netbeans.org/index_pt_BR.html
[6] Harvey M. Deitel, Paul J. Deitel; Java: Como Programar; Editora Bookman.
[7] Charles E. Leiserson, Clifford Stein, Ronald L. Rivest, Thomas H.
Cormen; Algoritmos: Teoria e Prática, Editora Campus.
[8] <completar>
37
38
Download