AVISOS - Avaliação em Época Normal |
---|
Esclarecimento de dúvidas:
|
Requisitos para desenvolvimento, material de apoio e actualizações do enunciado (ver informação completa em Projecto de Programação com Objectos):
|
Processo de avaliação (ver informação completa em Avaliação do Projecto):
|
Material de Uso Obrigatório |
---|
As bibliotecas po-uilib e o conteúdo inicial do repositório GIT são de uso obrigatório: |
|
A máquina virtual, fornecida para desenvolvimento do projecto, já contém todo o material de apoio. |
Uso Obrigatório: Repositório GIT |
Apenas se consideram para avaliação os projectos existentes no repositório GIT oficial.
Trabalhos não presentes no repositório no final do prazo têm classificação 0 (zero) (não são aceites outras formas de entrega). Não são admitidas justificações para atrasos em sincronizações do repositório. A indisponibilidade temporária do repositório, desde que inferior a 24 horas, não justifica atrasos na submissão de um trabalho. |
ÉPOCA NORMAL
O objectivo do projecto é desenvolver uma folha de cálculo.
A folha de cálculo é capaz de manipular números inteiros, cadeias de caracteres, referências entre células e funções sobre células. Além disso, permite também operações de corte, cópia e inserção (cut/copy/paste).
O número de linhas e de colunas da folha é fixo, sendo definidos na altura da criação. Os endereços (posições na folha: linha e coluna) têm início em 1 (um).
Uma célula é definida com base na sua posição na folha: CÉLULA ::= LINHA;COLUNA
Um intervalo de endereçamento (são sempre fechados) é definido entre duas células da mesma linha ou da mesma coluna: INTERVALO ::= CÉLULA:CÉLULA (as duas células pode ser a mesma).
Utiliza-se o termo “gama” para especificar indiscriminadamente uma célula única ou um intervalo de células.
Exemplo:
Por omissão, as células estão vazias (sem conteúdo). Os conteúdos admissíveis são: literais (números inteiros e cadeias de caracteres), referências para células e funções. As referências indicam-se com o símbolo “=” seguido do endereço da célula referenciada (Endereçamento). As funções indicam-se com o símbolo = ("igual"), o nome da função e a lista (possivelmente vazia) de argumentos entre parênteses (separados por vírgulas). Estão pré-definidas:
Considera-se que não existem dependências circulares, nem directas, nem indirectas, entre uma função e as células referidas pelos seus argumentos. Funções com argumentos inválidos (e.g., referem gamas com células vazias), têm valor inválido (apresentado como #VALUE), excepto nos casos especiais indicados.
Exemplos:
A aplicação permite manter informação sobre as entidades do modelo. Possui ainda a capacidade de preservar o seu estado (não é possível manter várias versões do estado da aplicação em simultâneo).
Deve ser possível efectuar pesquisas sujeitas a vários critérios e sobre as diferentes entidades geridas pela aplicação.
Uma base de dados textual com conceitos pré-definidos pode ser carregada no início da aplicação.
É possível inserir, apagar e mostrar conteúdos. É ainda possível copiar conteúdos entre células.
É possível pesquisar o conteúdo das células sob diferentes aspectos: (i) valores resultantes de avaliação; (ii) nomes de funções.
Existe um cut buffer por folha da aplicação e que permite as operações habituais (copiar, cortar, colar) entre células de uma dada folha.
As operações têm a semântica descrita a seguir.
O conteúdo da origem é copiado para o cut buffer e torna-se independente da fonte, i.e., alterações aos objectos originais não são propagadas para os que estão no cut buffer. O conteúdo anterior do cut buffer é destruído.
Esta operação funciona como a operação de cópia, mas o conteúdo original é destruído.
Esta operação insere o conteúdo do cut buffer numa gama da folha. Se o cut buffer estiver vazio, não é realizada qualquer operação. Se a gama for uma única célula, todo o cut buffer deve ser inserido a partir da célula especificada, até ser atingido o limite da folha de cálculo. Caso contrário, se a dimensão do cut buffer for diferente da da gama de destino, não insere nenhum valor.
O conteúdo do cut buffer não é alterado pela operação. Os objectos inseridos no destino são independentes dos que estão no cut buffer.
É possível guardar e recuperar o estado actual da aplicação, preservando toda a informação relevante, descrita acima.
A aplicação deve suportar o conceito de utilizador. Cada utilizador tem um identificador único na aplicação (o seu nome) e detém um conjunto de folhas de cálculo. Devido a necessidades futuras ainda não completamente especificadas, deve existir uma relação bidireccional de muitos para muitos entre utilizadores e folhas de cálculo.
A aplicação tem sempre um utilizador activo. Cada vez que se cria uma folha de cálculo na aplicação, ela deve ser associada ao utilizador activo. O utilizador com o nome root deve existir sempre. Por omissão, o utilizador activo é o utilizador com o nome root.
Devem ser possíveis extensões ou alterações de funcionalidade com impacto mínimo no código produzido: em particular, deve ser simples definir novas funções e novas pesquisas sobre células. O objectivo é aumentar a flexibilidade da aplicação relativamente ao suporte de novas funções.
A estrutura de armazenamento dos conteúdos da folha deve ser flexível, por forma a permitir a representação eficiente de folhas de diferentes dimensões. Assim, deve ser possível usar diferentes estratégias de representação do conteúdo, sem impacto no resto da aplicação. O objectivo deste requisito é optimizar o espaço ocupado em memória para guardar o conteúdo de uma folha de cálculo. Não é necessário concretizar para todas as situações, bastando ser suficientemente flexível para permitir novas implementações.
A determinação do valor de uma função que envolve uma gama pode ter um custo relativamente alto, caso envolva um número grande células. Caso nenhuma das células envolvidas tenha sido alterada desde a última vez que o valor da função foi determinado, então calcular o valor de novo é um desperdício. Pretende-se obter uma solução que optimize o número de vezes que uma função que envolva uma gama necessita de calcular o seu valor. Este requisito deve ser considerado apenas depois de tudo estar implementado e apenas vai ser tido em conta na entrega final do projecto.
A solução encontrada para optimizar o número de vezes que uma função tem que ser calculada deve ser extensível por forma a permitir que seja possível especificar outros tipos de funcionalidade que devem ocorrer quando o valor de uma célula muda de valor. Por exemplo, deveria ser possível concretizar o seguinte requisito sem que isso implicasse modificar as classes existentes (não é necessário implementar este exemplo): enviar um email a um dado utilizador cada vez que a célula em causa muda de valor. A sua solução deve ser flexível por forma a poder suportar diferentes tipos de entidades interessadas em modificações de uma célula sem que isso implique alterar o código já realizado.
A aplicação já deve estar preparada para suportar vários utilizadores, devendo já ter o código (ao nível da camada de domínio apenas) para a inserção de novos utilizadores.
Descreve-se nesta secção a funcionalidade máxima da interface com o utilizador. Em geral, os comandos pedem toda a informação antes de procederem à sua validação (excepto onde indicado). Todos os menus têm automaticamente a opção Sair (fecha o menu).
As operações de pedido e apresentação de informação ao utilizador devem realizar-se através dos objectos form e display, respectivamente, presentes em cada comando. As mensagens são produzidas pelos métodos das bibliotecas de suporte (po-uilib e xxl-app). As mensagens não podem ser usadas no núcleo da aplicação (xxl-core). Além disso, não podem ser definidas novas. Potenciais omissões devem ser esclarecidas antes de qualquer implementação.
De um modo geral, sempre que no contexto de uma operação com o utilizador aconteça alguma excepção, então a operação não deve ter qualquer efeito no estado da aplicação, excepto se indicado em contrário na operação em causa.
As excepções usadas na interacção (subclasses de pt.tecnico.uilib.menus.CommandException), excepto se indicado, são lançadas pelos comandos (subclasses de pt.tecnico.uilib.menus.Command) e tratadas pelos menus (instâncias de subclasses de pt.tecnico.uilib.menus.Menu). Outras excepções não devem substituir as fornecidas nos casos descritos.
Para o pedido de uma gama, utiliza-se a mensagem Prompt.address(). A excepção xxl.app.edit.InvalidCellRangeException é lançada se forem especificados endereços inválidos (excedem o limite da folha de cálculo ou representam gamas de células que não são intervalos verticais ou horizontais).
As acções deste menu permitem gerir a salvaguarda do estado da aplicação, abrir submenus e aceder a alguma informação global. A lista completa é a seguinte: Criar, Abrir, Guardar, Menu de Edição, Menu de Consultas.
As etiquetas das opções deste menu estão definidas na classe xxl.app.main.Label. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos em xxl.app.main.Prompt e xxl.app.main.Message.
Inicialmente, a aplicação não tem nenhuma folha, excepto quando usada a propriedade import (ver abaixo) para pré-carregar dados iniciais. Na situação em que a aplicação começa sem nenhuma folha, apenas são apresentadas as opções Criar e Abrir, pois as restantes necessitam da existência de uma folha. As opções irrelevantes nesta situação devem ser omitidas. O conteúdo da aplicação (toda a informação actualmente em memória) pode ser guardado para posterior recuperação (via serialização Java: java.io.Serializable). Na leitura e escrita do estado da aplicação, devem ser tratadas as excepções associadas. A funcionalidade é a seguinte:
Apenas existe uma folha na aplicação. Quando se abandona uma folha com modificações não guardadas (porque se cria ou abre outra), deve perguntar-se se se quer guardar a informação actual antes de a abandonar, através de Prompt.saveBeforeExit() (a resposta é obtida invocando readBoolean() ou de Form.confirm()).
Note-se que a opção Abrir não permite a leitura de ficheiros de texto (estes apenas podem ser utilizados no início da aplicação).
A opção Sair nunca implica a salvaguarda do estado da aplicação, mesmo que existam alterações.
Além das operações de manipulação de ficheiros, existem ainda no menu principal as seguintes opções.
Estas opções só estão disponíveis quando existir uma folha activa válida.
O menu de edição permite visualizar e alterar o conteúdo das células da folha activa. A lista completa é a seguinte: Visualizar, Inserir, Copiar, Apagar, Cortar, Colar e Visualizar cut buffer. As secções abaixo descrevem estas opções.
As etiquetas das opções deste menu estão definidas na classe xxl.app.edit.Label. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos em xxl.app.edit.Prompt e xxl.app.edit.Message.
Permite visualizar a gama especificada (Endereçamento), de acordo com os formatos abaixo. Se o conteúdo não for um literal, deve ser apresentado o seu valor e a sua expressão. Não deve ser apresentado qualquer conteúdo para células vazias.
Formatos (valor representa o valor final da célula, inteiro ou cadeia de caracteres, depois de efectuadas todas as avaliações):
linha;coluna|
linha;coluna|valor
linha;coluna|valor=expressão
linha1;coluna|conteúdo linha2;coluna|conteúdo linha3;coluna|conteúdo
linha;coluna1|conteúdo linha;coluna2|conteúdo linha;coluna3|conteúdo
É pedida a gama (Endereçamento). É especificado o conteúdo a inserir (Conteúdo), através da mensagem Prompt.contents(). O conteúdo é inserido em todas as células da gama. Se for inserido um nome de função inexistente, é lançada a excepção xxl.app.edit.UnknownFunctionException.
É pedida a gama (Endereçamento) cujo conteúdo deve ser copiado para o cut buffer.
É pedida a gama (Endereçamento) cujo conteúdo deve ser apagado.
É pedida a gama (Endereçamento). Esta acção corresponde à execução sequencial das acções descritas em Copiar e Apagar.
É pedida a gama (Endereçamento). Insere o conteúdo do cut buffer na gama especificada.
Permite visualizar o conteúdo do cut buffer. O formato de apresentação é o descrito em Visualizar.
O menu de consultas permite efectuar pesquisas sobre as células da folha activa, produzindo listas de células. Sempre que for feita uma consulta e nenhuma entidade satisfizer as condições associadas ao pedido, nada deve ser apresentado.
A lista completa das consultas é a seguinte: Procurar Valor, Procurar Função. As secções abaixo descrevem estas opções.
As etiquetas das opções deste menu estão definidas na classe xxl.app.search.Label. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos em xxl.app.search.Prompt e xxl.app.search.Message.
Pede-se o valor a procurar (Prompt.searchValue()) e apresentam-se os resultados.
O termo de pesquisa deve ser comparado com o valor avaliado de cada célula. As células que obedecem ao critério de procura devem ser apresentadas por ordem ascendente de linha e coluna e utilizando o formato especificado em Visualizar. Assim, considere-se o exemplo:
1;1|4 1;2|1 1;3|5 2;1|5=ADD(1;1,1;2) 2;2| 2;3|
Neste exemplo, uma pesquisa pelo valor 5 encontraria as células 1;3 e 2;1.
1;3|5 2;1|5=ADD(1;1,1;2)
Pede-se o segmento a procurar num nome de função (Prompt.searchFunction()) e apresentam-se os resultados ordenados (são apresentados como especificado em Visualizar), de forma ascendente, por nome de função, linha e coluna (por esta ordem).
Por omissão, quando a aplicação começa, não existe nenhuma folha activa. No entanto, além das opções de manipulação de ficheiros descritas no menu principal, é possível iniciar exteriormente a aplicação com um ficheiro de texto especificado pela propriedade Java import. Quando se especifica esta propriedade, é criada uma folha activa anónima que representa o conteúdo do ficheiro indicado.
No processamento destes dados, assume-se que não existem entradas mal-formadas. Assume-se que células não explicitamente referidas estão vazias (que também podem ser explicitamente definidas). Sugere-se a utilização do método String.split() para dividir uma cadeia de caracteres em campos.
As duas primeiras linhas definem o número de linhas e de colunas da folha de cálculo. As restantes linhas contêm sempre o formato linha;coluna|conteúdo (o campo conteúdo está descrito em Conteúdo).
No seguinte exemplo, o conteúdo do ficheiro inicial (test.import) correspondente à folha apresentada a seguir.
Exemplo de ficheiro de entrada textual |
---|
linhas=4
colunas=3
3;3|=ADD(3;1,3;2)
4;1|
1;1|5
1;2|49
2;1|25
2;2|43
2;3|=ADD(2;2,5)
3;1|10
3;2|=1;1
1;3|=ADD(2,5)
4;3|=AVERAGE(1;3:3;3)
4;2|
|
1 | 2 | 3 | |
---|---|---|---|
1 | 5 | 49 | =ADD(2,5) |
2 | 25 | 43 | =ADD(2;2,5) |
3 | 10 | =1;1 | =ADD(3;1,3;2) |
4 | =AVERAGE(1;3,3;3) |
A codificação dos ficheiros a ler é garantidamente UTF-8.
Usando os ficheiros test.import, test.in e test.out, é possível verificar automaticamente o resultado correcto do programa. Note-se que é necessária a definição apropriada da variável CLASSPATH (ou da opção equivalente -cp do comando java), para localizar as classes do programa, incluindo a que contém o método correspondente ao ponto de entrada da aplicação (xxl.app.App.main). As propriedades são tratadas automaticamente pelo código de apoio.
java -Dimport=test.import -Din=test.in -Dout=test.outhyp xxl.app.App
Assumindo que aqueles ficheiros estão no directório onde é dado o comando de execução, o programa produz o ficheiro de saída test.outhyp. Em caso de sucesso, os ficheiros das saídas esperada (test.out) e obtida (test.outhyp) devem ser iguais. A comparação pode ser feita com o comando:
diff -b test.out test.outhyp
Este comando não deve produzir qualquer resultado quando os ficheiros são iguais. Note-se, contudo, que este teste não garante o correcto funcionamento do código desenvolvido, apenas verificando alguns aspectos da sua funcionalidade.