14 de fevereiro de 2012

Aplicando recursos de localização em Asp.Net

por Tiago Oliveira*

Embora seja referenciado por uma palavra um tanto quanto estigmatizada - globalização - o fato é que o mundo ficou mesmo menor e os fabricantes de aplicações também passaram a levar isso em consideração. Ao planejar a construção de programas e sites, eles têm agora que incluir o conceito de localização na arquitetura, de uma forma que a aplicação se adeque à linguagem preferida pelo usuário sem que seja necessária uma reengenharia nas linhas de código.

O ASP.NET possui recursos de localização para que possamos fazer aplicações globalizadas, ou seja, para que a aplicação se adeque à região onde ela está sendo executada. A configuração utilizada pelo ASP.NET é a informada no navegador (no caso do IE, está no seguinte caminho : Opções de Internet/Geral/Idiomas), sendo considerado tanto o Idioma quanto a Região estipulados. Segue abaixo um exemplo de configuração:
en-US – Inglês região dos EUA.
pt-BR – Português região do Brasil.
As duas primeiras letras no código representam o Idioma e as duas últimas a região.

Agora vamos aplicar os recursos de localização disponíveis no ASP.NET para modificar esse comportamento padrão e fornecer um mecanismo para que o usuário opte pelo idioma de sua preferência na própria aplicação. Adicione um WebForm contendo 2 botões que, no caso, irão representar os possíveis idiomas suportados para visualização da aplicação : português e inglês.

Adicione um outro WebForm contendo alguns componentes Label, TextBox, etc. Para aplicar a localização às páginas da aplicação, o ASP.NET utiliza arquivos de Resources; por isso, vamos adicionar um arquivo de resource em nossa aplicação: clique no WebForm e selecione na guia Tools do Visual Studio a opção “Generate Local Resource”. Ao escolher essa opção. um arquivo de extensão .RESX com o mesmo nome da página será gerado dentro de uma pasta chamada App_LocalResources que será automaticamente adicionada ao seu projeto.

Dentro desse arquivo .RESX existe a relação de todos os componentes que comportam o recurso de localização, juntamente com a descrição dos campos. No nosso exemplo, esse arquivo irá representar a versão em português da aplicação; para gerarmos o arquivo contendo a versão em inglês, faça uma cópia do arquivo NomeDaSuaPagina.aspx.resx gerado pelo Visual Studio e altere o nome para NomeDaSuaPagina.aspx.en-US.resx. Nesse novo arquivo, faça a tradução dos campos para o Inglês.

No WebForm onde colocamos os 2 botões para identificar os idiomas, iremos passar a localização através de Query String, conforme código abaixo associado ao clique de cada um dos botões:
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
Response.Redirect("Conteudo.aspx?Language=pt-BR");
}

protected void ImageButton2_Click(object sender, ImageClickEventArgs e)
{
Response.Redirect("Conteudo.aspx?Language=en-US");
}
Na página Conteudo.aspx (representando a página principal da aplicação), precisamos inicializar a cultura de exibição para considerar a que passamos por parâmetro e não aquela que está configurada no navegador. Para isso precisamos sobrescrever o método InitializeCulture da página e ajustar a variável interna UICulture, que é a responsável por controlar o idioma em que a aplicação está sendo exibida:
protected override void InitializeCulture()
{
UICulture = Request.QueryString["Language"];
base.InitializeCulture();
}
Ao exibir os textos da página, o ASP.Net passará a considerar automaticamente o conteúdo do arquivo .RESX referente ao idioma e região escolhidos.

* Tiago Oliveira é desenvolvedor na ABC71, onde trabalha com os módulos fiscais, de faturamento e de vendas.


10 de fevereiro de 2012

Microsoft abre extensão do C++ para uso em outros compiladores

Já há algum tempo que os computadores vêm sendo montados com placas gráficas - as chamadas GPUs - cada vez mais poderosas. No início, elas eram requisitadas apenas por quem apreciava jogos no PC pois esse tipo de software exige cálculos complexos intensos para apresentar a parte gráfica, o que usa massivamente as GPUs. Essa história começou a mudar com o Windows Vista, quando o próprio sistema operacional passou a fazer uso mais intenso da capacidade dessas placas, oferecendo aos usuários uma experiência visualmente mais agradável no uso do computador. Com isso, a preocupação de melhorar a apresentação dos programas aproveitando a GPU entrou na lista das empresas desenvolvedoras de software.

Já que se trata de uma CPU extra no computador, muitas vezes a GPU ainda acaba sendo sub utilizada. Mas, acessar plenamente os recursos das GPUs não é uma tarefa trivial. Atenta a isso, a Microsoft vem trabalhando em uma biblioteca para facilitar a utilização desses recursos por qualquer desenvolvedor.

Na verdade, a solução proposta pela Microsoft é estender a linguagem C++, introduzindo nela uma forma nativa e transparente de se ter acesso aos recursos da GPU, fornecendo junto os mecanismos de controle inerentes à computação paralela - notadamente, a sincronização de processamentos.

Abaixo segue uma tradução da reportagem publicada pela Infoworld dando mais detalhes dos planos da Microsoft. A reportagem original em inglês pode ser acessada no link Microsoft opens C++ extension for other compilers.
A Microsoft abriu sua especificação do C++ AMP de modo que ela agora pode ser usada por compiladores de outros fabricantes para aproveitar o poder das GPUs (graphics processing units).

"Estamos vendo cada vez mais gente procurando tirar proveito das GPUs em suas aplicações", disse Tony Goodhew, gerente de produto na Microsoft para o Visual Studio.

A proposta do C++ Accelerated Massive Parallelism (C++ AMP), primeiro desenvolvido para o Visual Studio 11 e liberado junto com a versão preliminar desse software para desenvolvedores em setembro, é permitir que os programadores C++ possam escrever programas que executem em paralelo em ambientes computacionais heterogênios.

Agora, ele é livre para ser utilizado por outros fabricantes de compiladores C++, como a Embarcadero, Intel, e a Free Software Foundation.

Cada vez mais, os fabricantes de GPU, tais como a Nvidia, vêm oferecendo suas GPUs para incrementar a performance de programas, auxiliando a CPU a concluir tarefas que demandam muitos cálculos. Tradicionalmente, programar para computação paralela tem sido uma tarefa complicada, apenas dominada por codificadores altamente especializados que normalmente trabalharam com super computadores em laboratórios ou empresas do mercado financeiro.

Com o C++ AMP, "Não precisarei ser um especialista altamente treinado para alcançar esse hardware," diz Goodhew.

Os engenheiros da Microsoft trabalharam para minimizar a quantidade de mudanças em relação à versão canônica do C++. O C++ AMP realmente traz algumas restrições adicionais necessárias quando se executa um código através de múltiplos processadores. Ele também tem recursos adicionais, como tipos array multidimensionais, bem como suporte para transferência assíncrona em memória, memória compartilhada e sincronização.

Em sua implementação, a Microsoft usou a biblioteca DirectCompute para DirectX do Windows para interagir com as GPUs, embora os fabricantes de compiladores possam se valer de outras interfaces para GPU, como a Cuda da Nvidia. Segundo Goodhew, embora esta versão do AMP tenha sido projetada especificamente para GPUs, ela também assenta as bases para eventualmente suportar outros tipos de aceleradores de hardware.

A especificação está publicada sob a licença Microsoft Community Promise.

A Microsoft lançou o C++ AMP em setembro passado, como parte da versão prévia para desenvolvedores do Visual Studio 11, depois de ter anunciado em junho a intenção de abrir a especificação para o mercado. A próxima release do Visual Studio 11 Beta incluirá suporte adicional para a especificação, que foi apresentada pela empresa sexta-feira na conferência GoingNative 2012 C++, ocorrida semana passada em Redmond, Washington.

A companhia está trabalhando com o comitê de padronização do C++ na esperança de que o grupo usará as ideias do C++ AMP como parte do núcleo da especificação da linguagem C++. Levará um tempo até que isso ocorra, entretanto, dado o longo intervalo entre as atualizações no padrão. A versão mais recente do padrão para o C++, informalmente chamada de C++2011, foi lançada no ano passado, no que foi a primeira grande mudança em quatro anos.

O documento com a especificação do C++ AMP está disponível no formato PDF neste link.

31 de janeiro de 2012

Informações sobre rotas com a versão 3 da API do Google Maps

No ano passado eu publiquei dois posts mostrando como traçar rotas usando a versão 3 da API do Google Maps. O primeiro tratava de um cenário básico onde consideramos um endereço de origem e outro de destino; o segundo avançava um passo ao permitir a inclusão de um ou mais pontos intermediários ao trajeto. Por razões distintas, várias pessoas me perguntaram como é possível obter a distância total entre a origem e o destino em uma rota, independendo se vamos efetivamente exibir a rota traçada.

Pra refrescar a memória, o quadro a seguir ilustra os comandos e estruturas básicos necessários pra trabalharmos com uma rota.
var directionsService, directionsRenderer;
var enderDe, enderAte;

directionsService = new google.maps.DirectionsService();
directionsRenderer = new google.maps.DirectionsRenderer();
directionsRenderer.setMap(map);

enderDe = 'ALAMEDA SANTOS, 1000, SÃO PAULO - SP, 01418-9028';
enderAte =
'AVENIDA NAÇÕES UNIDAS, 17-17, BAURU - SP, 17013-035';

var request = {
origin:endDe,
destination:endPara,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};

directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsRenderer.setDirections(response);
}
});)

A linha directionsRenderer.setDirections (response) usa o objeto response para traçar automaticamente a rota no mapa. Esse objeto é do tipo DirectionsResult e é montado pela função route antes de ser repassado como response à nossa função de callback. No entanto, você pode usar manualmente as informações contidas em response sem que a rota precise ser exibida.

De acordo com a documentação, o DirectionsResult possui como única propriedade um Array chamado routes contendo a lista de rotas encontradas pelo serviço para atender a requisição feita. Cada elemento dessa lista traz detalhes de uma rota específica, descrita na forma de um objeto DirectionsRoute, o que inclui detalhes de cada trecho do trajeto, como a distância de cada um (em metros) e o tempo estimado usando o tipo de locomoção escolhido.

Com isso, podemos facilmente obter a distância a ser percorrida para chegar ao destino usando a rota em questão:
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var distancia;
var rota = response.routes[0]; /* Primeira rota */
var etapa = rota.legs[0]; /* única etapa dessa rota */

distancia = etapa.distance.value;

alert ('Distância Total => ' + distancia.toString() + ' metros.');
}
});)

A propriedade legs destrincha cada etapa do trajeto usando objetos do tipo DirectionsLeg para descrevê-las. Por etapa entende-se o deslocamento necessário entre dois endereços. Assim, se você estipulou apenas a origem e o destino, haverá uma única etapa e, por conseguinte, uma única posição em legs. Por outro lado, se você adicionou pontos de referência usando o waypoints na requisição (veja esse post para mais detalhes), haverá uma nova etapa descrevendo como chegar a cada ponto. Nesse caso, será preciso percorrer todas as posições, somando a distância de cada etapa para se obter a distância total da rota:
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var distancia = 0;
var rota = response.routes[0]; /* Primeira rota */
var etapa, i;

for (i = 0; i < rota.legs.length; i++)
{
/* Obtem cada etapa */
etapa = rota.legs[i];
distancia += etapa.distance.value;
}

alert ('Distância Total => ' + distancia.toString() + ' metros.');
}
});)

O detalhamento do caminho a ser seguido dentro de cada etapa do trajeto pode ser acessado através da propriedade steps. Cada passo também possui sua distância mas a soma delas já está consolidada na própria etapa (leg). Tenha em mente que, para certos trajetos, pode acontecer de as informações de distância e duração não estarem disponíveis. Por questão de simplicidade, os scripts acima não levam isso em conta. Um exemplo completo dos recursos mostrados até agora pode ser visto na página abaixo, cujo código fonte está neste link:

Um outro ponto importante a ser lembrado é que a função route é assíncrona. Isto significa que a função de callback que passamos a ela poderá ser executada depois da linha de código imediatamente seguinte ao route. Assim, se tiver que comparar as distâncias de várias rotas, terá que montar uma forma de sincronizar os cálculos para que a comparação só ocorra depois da execução de todos os callbacks envolvidos. Esse efeito normalmente é conseguido através da função javascript setinterval, verificando a cada segundo, por exemplo, se as rotas já estão prontas.

Mais Informações
Traçando rotas com a versão 3 da API do Google Maps - Parte I e Parte II, Google Maps JavaScript API V3

23 de janeiro de 2012

Trabalhando com Ações em Delphi e C++ Builder

As operações que um usuário pode executar em programas com interface visual podem estar disponíveis de diversas maneiras. As formas mais óbvias e mais utilizadas são os menus, barras de ferramentas, menus de contexto, botões espalhados pela interface e, mais recentemente, os ribbons introduzidos pela interface do Microsoft Office. Com essa variedade de formas de se acessar uma operação, é bastante comum que esse acesso esteja disponível em mais de um lugar.

Do ponto de vista do programador surge então uma questão: qual a melhor maneira de se gerenciar as operações em uma aplicação, notadamente aquelas que estarão acessíveis por mais de uma via ? A solução para quem desenvolve com Delphi ou C++ Builder é um componente que já existe há um bom tempo nesses ambientes, chamado TActionManager.

Como diz o nome, o objetivo do TActionManager é gerenciar as operações que estarão disponíveis para o usuário em uma aplicação, centralizando a configuração básica de cada operação. O componente permite organizar as operações por afinidade (relativas a arquivo, edição, visualizar ou ajuda, por exemplo); informar textos e imagens descritivos da operação a fim de manter a uniformidade visual independente da forma de acesso escolhida; sinalizar se a operação está ativa ou mesmo visível.

E como é que isso tudo se conecta ? Alimentar o TActionManager com operações faz com que o IDE crie instâncias de um outro objeto, o TAction. Cada TAction corresponde a uma operação - ou ação - isolada, independente da interação necessária para ativá-la. Essa ação pode então ser associada à propriedade Action existente em diversos componentes - itens de menu, botões, itens em barras de ferramenta, etc.

Entretanto, certos componentes - como o TActionMainMenuBar e o TRibbon - são configurados diretamente com uma instância do ActionManager e não com ações individuais.

Para dar manutenção nas ações gerenciadas pelo ActionManager, dê um duplo clique nele. Será exibida uma caixa de diálogo como a reproduzida abaixo, onde é possível criar novas ações, excluí-las e rearranjá-las. Selecionar uma ação fará com que o Object Inspector apresente as propriedades relativas a ela.
Configuração do Action Manager
Há umas poucas propriedades no ActionManager e elas não são obrigatórias; destaco abaixo aquelas que são mais utilizadas:
Images e DisabledImages são TImageList contendo, respectivamente, a imagem que deve ser vinculada a uma ação quando ela está ativa e quando está desabilitada. Em ambos os casos, as imagens devem ser pequenas - 16 x 16 pixels. Uma das propriedades de uma ação é o índice da imagem a ser usada; como só há um índice, a imagem correspondente à ação deve estar exatamente na mesma posição em todas as listas de imagens configuradas.
LargeImages e LargeDisabledImages são os TImageList que contem imagens grandes - 32 por 32 pixels - para as ações configuradas nesse gerenciador. A primeira lista vincula imagens a ações ativas enquanto a segunda traz as imagens grandes para ações desabilitadas. Lembre-se que as imagens relativas a uma ação devem estar na mesma posição, conforme dito no tópico anterior.
State: Permite desativar todas as ações de um única vez, impedindo-as de serem disparadas.
Use a propriedade ActionBars para criar barras de ferramentas associadas ao gerenciador.
FileName indica o caminho completo para um arquivo que armazernará a configuração dinâmica feita pelo usuário final em tempo de execução.

Como se depreende do exposto acima, o gerenciador de ações pode ser usado em conjunto com o TCustomizeDlg para permitir ao usuário final reorganizar as barras de ferramentas.

Uma vez que o gerenciador está preparado, podemos acrescentar-lhe as ações e configurá-las. A lista abaixo mostra as principais propriedades do TAction:
Use Caption para informar o texto padrão para a ação. É esse texto que será usado num item de menu ou como texto de um botão onde a ação for vinculada.
Use Category para organizar as ações, agrupando-as por afinidade, o que facilita a manuntenção de ações tanto para o programador quanto para o usuário final - caso a funcionalidade de configuração seja disponibilizada a ele.
ImageIndex é a posição das imagens a serem usadas para representar a ação em diversos contextos. Cada ação terá à sua disposição o mesmo índice em cada uma das 4 listas existentes no gerenciador de ações.
Uma combinação de teclas pode ser atribuída em Shortcut. Essa combinação é um método alternativo para executar a ação associada a ela.
O evento OnExecute é usado para centralizar a execução da ação. Assim, não é preciso acrescentar código em nenhum outro ponto do programa nem responder a outros eventos; basta configurar a propriedade Action existente no componente que desejar disparar a ação - menus e botões, por exemplo.
Enabled permite habilitar ou desabilitar uma ação individual de forma centralizada. Isto é, altere essa propriedade para que todas as possibilidades de se executar a ação sejam afetadas de uma só vez.
Modifique a propriedade Visible para esconder ou mostrar uma ação de uma só vez em todos os contextos nos quais ela estiver disponível.