quarta-feira, 29 de julho de 2009

Será que não é possivel utilizar o Base do OpenOffice em ambiente multi-utilizador?


Em primeiro lugar - numa forma, ou, mais precisamente num contexto, está correto.

Este contexto particular, é quando se utiliza uma base para criar todos os arquivos, isto é, os formulários, consultas, relatórios e as próprias tabelas de armazenamento de dados num único arquivo. Só que este não é o único contexto em que o Base pode ser utilizado.

Antes de falar do Base num ambiente multi-utilizador, porém, vamos perder um minuto com o MS Access a trabalhar no mesmo ambiente.

O MS Access também pode ser utilizado como um monolítico arquivo contendo os formulários, consultas, relatórios, tabelas e base de dados e código VBA. É possível construir esse arquivo e colocá-lo numa unidade compartilhada e mapear outros PC's de forma que os mesmos possam “ver” este arquivo e, ao fazê-lo, ter múltiplos utilizadores a partilhar o acesso a essa base de dados. Mas isso coloca uma grande sobrecarga sobre a rede e sobre o computador que hospeda o arquivo. Nessa configuração o número real de utilizadores a que se pode dar privilégios de leitura/gravação e acesso simultâneo à base de dados da aplicação é bastante limitada.

Na verdade, não é considerada a forma adequada para implementar um sistema multi-utilizador MS Acccess. Pelo contrário, é comum a rotina de o dividir em front end (formulários, consultas, relatórios e código VBA), e back-end (tabelas de armazenamento de dados reais) acabando por criar dois arquivos separados fisicamente.

Normalmente, isso produz um arquivo *. mdb (ou *. accdb), o "back-end", que depois é armazenado no disco partilhado e um ou mais arquivos *. mde , os "front-end" .Ideal para efeitos de desempenho e para aumentar o número de utilizadores simultâneos que podem ser suportados num arquivo *. mde separado .

A Microsoft criou uma série de ferramentas só para ajudar a fazer isso e dedicou uma boa parte do espaço nos seus sites de apoio ao MS Access explicando como usar e como implantá-los desta forma. Juntamente com estas ferramentas Microsoft também fornece as ferramentas necessárias para o “upsize” da sua base de dados *. mdb ou *. accdb (o seu backend) para SQL Server, contendo os dados reais .

Então - agora vamos olhar o Base.

O OpenOffie.org Base é, arquitectonicamente, diferente do MS Access no que diz respeito à base de dados e ao motor utilizado.

O MS Access pré 2007 tem sempre o MS Jet Database Engine envolvido, mesmo quando se está 'ligando' através para uma base de dados SQL Server.

Essa é a velha arquitectura *. mdb. Nas últimas versões do MS Access utilizando o tipo de arquivo *. accdb o motor já não é MS Jet, mas ainda é um único motor que está sendo utilizado, enquanto um arquivo *accdb é usado.

No Base, por outro lado, é o arquivo *.odb que contrata directamente uma ligação a uma base de dados. O motor de base de dados é o HSQLdb RDBMS, distribuído com OpenOffice.org, capaz de armazenar as suas tabelas embutidas no arquivo *.odb. Mas, fundamentalmente, o Base está tratando isto como apenas mais uma opção para um motor de base de dados - de modo que se poderia, facilmente, ter uma base de dados HSQLdb ,utilizando o motor , funcionando em modo de arquivo em disco, com os dados armazenados no arquivos separados num diretório, ou correr, como uma rede acessível partilhada num 'servidor'. Pode-se também usá-lo para se conectar a qualquer motor de base de dados ( JDBC ou ODBC ou ADO)

Ao usar o Base, para "ligar" a uma rede de base de dados destes motores (que poderia ser realmente no seu localhost), o arquivo *.odb preenche , na realidade,o mesmo papel que o arquivo MDE no MS Acess. Por outras palavras, permite que se armazenem os formulários, consultas, relatórios e, após o OpenOffice. 3.0, as bibliotecas de script, directamente dentro do arquivo. Com as anteriores versões do OpenOffice(e ainda no 3.0, se se quiser), os scripts eram armazenados em separado, em biblioteca de arquivos compartilháveis.

Nesta implantação multi-utilizador do Base poder-se-á colocar uma cópia deste arquivo *.odb em cada computador que esteja usando o base de dados aplicativo. Mais uma vez, isso é análogo ao regime recomendado para implantação MS Access também oferece a capacidade de cada utilizador criar as suas próprias cópias locais de consultas e relatórios.

Existe porém uma diferença, isto é, quando os *. mdb ou *. accb do arquivo de compartilhamento é usado pelos diferentes arquivos *. mde existe um intermediário de dados do motor a ser utilizado (MS Jet, por exemplo) mas quando se implementar os arquivos *.odb em várias máquinas a ligar a um servidor de rede de dados é a ligação directa - não há meio passo para os dados a tomar.

A próxima diferença é de custo, evidentemente. No caso do MS Access é dizer que cada utilizador tem que ter uma licença para o MS Access ou que exista uma licença para desenvolvimento e distribuição das suas base de dados. Se se desejar utilizar o SQL Server como base de dados então tem-se o custo da base de dados e os custos de um servidor MS Windows para a executar. (Até podemos supor que um deles já exista)

Para OpenOffice.org e Base. 5, 10 ou 100 utilizadores, realmente não interessa.

Assim - Base em um ambiente multi-utilizador? Sim - ainda não é comum e, de certeza, existem lacunas no conjunto, em comparação com MS Access, mas a aplicação é um conjunto muito mais à frente hoje em dia, do que foi quando se estreou com o OpenOffic 2.0 e, com o 3.1 e extensões disponíveis, como o Sun Report Builder, não será preciso esperar demasiado para que haja uma muito simples e directa resposta a essa questão - simplesmente - "Sim, pode-se fazê-lo" - o facto é que a resposta é – "Sim pode-se fazer isso hoje, mas você vai ter em mãos uma tarefa árdua..."

(Tradução livre de texto em inglês.Veja o original aqui)

quinta-feira, 23 de abril de 2009

Usar o controle Calendário no Base do Open Office


1. Arraste um campo de data para o formulário
2. Click duas vezes no controle para o editar
3. No separador "Geral" assinale "Pendente" como "Sim"


Assim poderá usar o calendário para escolher a data que pretende (ver figura acima)

terça-feira, 31 de março de 2009

O Limpador

Para quê preocupar-se em limpar todo o lixo que se vai acumulando no computador (ficheiros temporários, ficheiros temporários de internet, etc, etc), se existe um programa que faz tudo isso?

Além disso também corrige os erros do registo, pode desinstalar programas, etc.

Por isso recomendo o CCleaner.

Pode fazer o download dele aki

quarta-feira, 25 de março de 2009

Macros para o BASE-Open Office


REM Macro semelhante ao AutoExec do ACCESS

Sub AutoExec
On Error Goto HandleError
Dim LastFrame As Object
Dim NumFrames As Integer
Static FormDocs As Object
Dim DBDoc As Object
Dim ImpName As String
Dim DataSource As Object
Dim Conn As Object
Dim Args(1) As New com.sun.star.beans.PropertyValue
Dim FormName As String
Dim FormDoc As Object
FormName="SWITCHBOARD" 'Mude aqui para o Forms de Abertura da Aplicação
ImpName="com.sun.star.comp.dba.ODatabaseDocument"
NumFrames=StarDesktop.Frames.Count
LastFrame=StarDesktop.Frames.getByIndex(NumFrames-1)
If LastFrame.Frames.Count>1 Then
Exit Sub
End If
If Not (LastFrame.Controller.Model.ImplementationName=ImpName) Then
Exit Sub REM not a db doc
End If
DataSource=LastFrame.Controller.DataSource
DBDoc=DataSource.DatabaseDocument
FormDocs=DBDoc.FormDocuments
Conn=DataSource.getConnection("","") REM no user/password
Args(0).Name="ActiveConnection" : Args(0).Value=Conn
if FormDocs.hasByName(FormName) Then
FormDoc=FormDocs.loadComponentFromURL(FormName,"_self",2,Args() )
FormDoc.CurrentController.Frame.ContainerWindow.setFocus()
End If
HandleError:
If Err<>0 Then
Exit Sub
End If
End Sub

REM Macro generica para abrir qualquer forms

function OpenForm( formContainer as variant, oConnection as variant, sFormName as string) as variant
Dim aProp(1) As New com.sun.star.beans.PropertyValue
aProp(0).Name = "ActiveConnection"
aProp(0).Value = oConnection
aProp(1).Name = "OpenMode"
aProp(1).Value = "open"
OpenForm = formContainer.loadComponentFromURL(sFormName,"_blank",0,aProp())
end function

function getFormsTC() as variant
getFormsTC = thisComponent.Parent.getFormDocuments
end function

function getConnectionTC() as variant
getConnectionTC = thisComponent.Drawpage.Forms(0).ActiveConnection
end function

REM Macro para abrir um forms específico

sub OpenForm_fTESTE( oev as variant )
sFormName = "fTESTE" ' Mude aqui o nome do seu forms
OpenForm( getFormsTC, getConnectionTC, sFormName )
end sub

REM Macro generica para abrir qualquer report

function getConnectionTC() as variant
getConnectionTC = thisComponent.Drawpage.Forms(0).ActiveConnection
end function

function OpenReport( reportContainer as variant, oConnection as variant, sReportName as string) as variant
Dim aProp(1) As New com.sun.star.beans.PropertyValue
aProp(0).Name = "ActiveConnection"
aProp(0).Value = oConnection
aProp(1).Name = "OpenMode"
aProp(1).Value = "open"
OpenReport=reportContainer.loadComponentFromURL(sReportName,"_blank",0,aProp())
end function

function getReportsTC() as variant
getReportsTC = thisComponent.Parent.getReportDocuments
end function

REM Macro para abrir um report especifico

sub OpenReport_rREPORT1( oEv as variant )
sReportName="rREPORT1" ' Mude aqui o nome do seu Report
OpenReport( getReportsTC, getConnectionTC, sReportName )
end sub

REM Macro para abrir um formulário sem abrir a Base de dados

Sub openOnlyfMOVIMENTOS
oContexto = CreateUnoService("com.sun.star.sdb.DatabaseContext")
oFonte = oContexto.getByName("contabilidade")'Mude aqui o nome da base de dados
oForms = oFonte.DatabaseDocument.FormDocuments
oAConnection = oFonte.getConnection("","")

Dim pProp(1) As New com.sun.star.beans.PropertyValue
pProp(0).Name = "ActiveConnection"
pProp(0).Value = oAConnection
pProp(1).Name = "OpenMode"
pProp(1).Value = "open"
oForm = oForms.loadComponentFromURL("fMOVIMENTOS", "_blank", 0, pProp())'Mude aqui o nome do seu formulário
End Sub


REM Macro para abrir um relatório sem abrir a base de dados

Sub openOnlyrMOVIMENTOS
oContexto = CreateUnoService("com.sun.star.sdb.DatabaseContext")
oFonte = oContexto.getByName("contabilidade")'Mude aqui o nome da base de dados
oReports = oFonte.DatabaseDocument.ReportDocuments
oAConnection = oFonte.getConnection("","")

Dim pProp(1) As New com.sun.star.beans.PropertyValue
pProp(0).Name = "ActiveConnection"
pProp(0).Value = oAConnection
pProp(1).Name = "OpenMode"
pProp(1).Value = "open"

oReport = oReports.loadComponentFromURL("rMOVIMENTOS", "_blank", 0, pProp())' Mude aqui o nome do seu relatório
End Sub


REM Macro para apagar valores de uma tabela

Sub DeleteAllFromTEST_TABLE2

Dim DatabaseContext As Object
Dim DataSource As Object
Dim Connection As Object
Dim Statement As Object
Dim ResultSet As Object
DatabaseContext = createUnoService("com.sun.star.sdb.DatabaseContext")
DataSource = DatabaseContext.getByName("teste")
Connection = DataSource.GetConnection("","")
Statement = Connection.createStatement()
ResultSet = Statement.executeQuery("DELETE FROM TEST_TABLE2 WHERE ID = 2")
End Sub

REM Macro para inserir valores numa tabela

Sub InsertFromTEST_TABLE2
Dim DatabaseContext As Object
Dim DataSource As Object
Dim Connection As Object
Dim Statement As Object
Dim ResultSet As Object
DatabaseContext = createUnoService("com.sun.star.sdb.DatabaseContext")
DataSource = DatabaseContext.getByName("teste")
Connection = DataSource.GetConnection("","")
Statement = Connection.createStatement()
ResultSet = Statement.executeQuery("INSERT INTO TEST_TABLE2(ID,F1,F2,F3)VALUES (1,'a','abc','abcd')")
End Sub

REM Macro para inserir valores numa tabela provenientes de outra

Sub SelectInsertfromTEST_TABLE2
Dim DatabaseContext As Object
Dim DataSource As Object
Dim Connection As Object
Dim Statement As Object
Dim ResultSet As Object
DatabaseContext = createUnoService("com.sun.star.sdb.DatabaseContext")
DataSource = DatabaseContext.getByName("teste")
Connection = DataSource.GetConnection("","")
Statement = Connection.createStatement()
ResultSet = Statement.executeQuery("INSERT INTO TEST_TABLE2(ID,F1,F2,F3)SELECT ID, F1,F2,F3 FROM TEST_TABLE3")
End Sub

REM Macro para Alterar uma Tabela

sub UpdateTEST_TABLE2
Dim DatabaseContext As Object
Dim DataSource As Object
Dim Connection As Object
Dim Statement As Object
Dim ResultSet As Object
DatabaseContext = createUnoService("com.sun.star.sdb.DatabaseContext")
DataSource = DatabaseContext.getByName("teste")
Connection = DataSource.GetConnection("","")
Statement = Connection.createStatement()
ResultSet = Statement.executeQuery("UPDATE TEST_TABLE2 SET F1=100, F2=200 WHERE ID=1")
End sub

terça-feira, 24 de março de 2009

Open Office 3.0 - Base



Quando se entra no BASE, tem-se a sensação que, de facto, tudo é muito parecido com o ACCESS, o programa de base de dados do MsOffice.

Realmente temos:

- Tabelas
- Consultas
- Formulários
- Relatórios

Módulos que existem no ACCESS, não temos aqui!!!
Veremos mais tarde que os módulos podem ser criados em livrarias e componentes.

Criar tabelas no BASE é bastante fácil (tem até um assistente!).

Consultas de selecção também é extremamente fácil e com uma interface (que depois produz o sql) também bastante parecida com o ACCESS, mas consultas de modificação, inserção ou eliminação, essas, pura e simplesmente, não existem!

Quando entramos nos formulários, também não se nota grande diferença se nos cingirmos ao trivial. Os wizards não são maus, se seguirmos os modelos que temos à disposição.
Notámos no entanto uma grande diferença entre o ACCESS e o BASE.
Alterar um formulário constituído com o assistente é extremamente difícil, pois os controlos parecem ter vontade própria e diminuir-lhes ou aumentar-lhes o tamanho, alinhá-los de uma forma pessoal, é tarefa que parece impossível.
Por outro lado, os wizards parecem restringir-se aos componentes principais porque, por exemplo, no ACCESS, ao arrastarmos um botão para um formulário o ACCESS sabe que há um conjunto de tarefas padrão (abrir outro formulário, imprimir um relatório, etc) que podemos querer executar ao premir esse botão e pergunta-nos logo qual queremos efectuar. Só se não for nenhuma das tarefas padrão precisamos escrever algum código.
Aqui não, teremos sempre que escrever o código das tarefas que queiramos levar a cabo!

Os relatórios parecem-nos a ferramenta mais pobre no que diz respeito ao BASE (mesmo com o Sun Report Builder o seu aspecto não tem nada a ver com os relatórios conseguidos com o ACCESS, embora com tempo e estudo (muito) se possam conseguir grandes melhoras).
Também aqui, quando construídos com o assistente, os controlos parecem ter vontade própria e dispô-los à nossa maneira é uma tarefa quase impossível.

Outra coisa que notámos falta no BASE, foi algo parecido com o Intellisense (que por ser patenteado pela Microsoft deve ser muito difícil de "imitar"!) e antevemos grandes dificuldades para quem queira fazer um programa mais ou menos ambicioso sem ter um curso de programação na linguagem.

Também falta no Base um utilitário para dividir os ficheiros em "Front End" e "Back End" para que o mesmo possa ser utilizado em ambiente de multi-utilizador.

Algo que também ainda nos suscita algumas dúvidas é se um projecto desenvolvido no Base num computador, o mesmo funcionará noutro, tal e qual, principalmente se o mesmo contiver macros.
Será que, tal como no ACCESS, o mesmo transporta consigo todas as funcionalidades?

Enfim, se tínhamos notado algumas dificuldades no CALC, no BASE, uffffffffffff!

Temos gasto horas (dias?) na net em busca de ajuda e...mesmo em inglês!

Mas já algo foi conseguido e será trazido aqui oportunamente.

terça-feira, 10 de março de 2009

Macro para actualizar tabelas dinâmicas no CALC do OpenOffice

Nem de propósito, mal tínhamos completado o artigo anterior, descobrimos a macro necessária para actualizar automaticamente todas as tabelas dinâmicas de uma folha de cálculo do CALC (só em inglês conseguimos encontrar)

Pedindo desculpa por não saber a autoria, ela aí fica:

REM ***** BASIC *****
Sub refresh_DBRanges_And_Pilots
REM disable auto-calculation:
bAutoCalc = thisComponent.IsAutomaticCalculationEnabled
thisComponent.enableAutomaticCalculation(False)
oDBRangesEnum = thisComponent.DatabaseRanges.createEnumeration()
refresh_Enumeration(oDBRangesEnum)
oSheetsEnum = thisComponent.Sheets.createEnumeration()
refresh_All_DataPilots(oSheetsEnum)
REM reset auto-calculation to previous state:
thisComponent.enableAutomaticCalculation(bAutoCalc)
End Sub
Sub refresh_All_DataPilots(oSheetsEnum)
REM Bug: Disregards pilots created from datasource
while oSheetsEnum.hasMoreElements()
oSheet = oSheetsEnum.nextElement()
oDPEnum = oSheet.DataPilotTables.createEnumeration()
refresh_Enumeration(oDPEnum)
wend
End Sub
Sub refresh_Enumeration(oEnum)
while oEnum.hasMoreElements()
oNext = oEnum.nextElement()
oNext.refresh()
wend
End Sub


Para os que não sabem como utilizar macros, prometemos que voltaremos ao assunto.

Open Office 3.0 - Calc

Tal como prometemos iremos experimentar, a fundo, cada componente do Open Office.

Resolvemos começar pelo CALC, a folha de cálculo.

Como já díspunhamos de uma folha de cálculo para o Orçamento familiar elaborada em Excel, resolvemos elaborar, de raiz, a mesma folha de cálculo no Calc.

Assim, ao mesmo tempo que testávamos o Calc, fazíamos logo a comparação do Calc com o Excel.

A folha de cálculo será um esboço de um livro mensal, com várias folhas, onde constarão:


1ª. Folha

- Receitas do mês ( Ordenados, etc)

- Despesas do mês ( Habitação, transportes, etc.etc)

Uma Folha para cada rúbrica mensal, constituida por:

- Data do movimento

- Descrição do movimento

- Saidas

- Entradas

- Total de Entradas

- Total de Saidas

- Saldo

Última Folha

- Saldos de Despesas ( Habitação, transportes, etc)

- Saldos de Receitas (Bancos, caixa, devedores, etc)

A primeira página ficará ligada a cada primeira linha de cada página pelos valores destinados a cada rúbrica.

Cada página de cada rúbrica conterá uma tabela dinâmica que calculará os totais de entradas e saidas e, por diferença, calcularemos o saldo que, por sua vez ligaremos à página dos Saldos, à linha respectiva.

Na folha dos saldos haverá, claro, um total de receitas e um total de despesas, bem como uma diferença entre elas para sabermos, sempre, se tudo está certo (se a diferença for diferente de 0 é porque algo correu mal).

Vejamos entao como construimos o livro:

A primeira folha ficou assim:

Cada folha, referente a cada rúbrica ficou assim:

Ligámos a primeira folha com as seguintes, da seguinte forma:

  • Clickámos com o botão direito do rato no valor da rúbrica a copiar

  • Escolhemos o campo da página da rúbrica para onde queriamos colar o resultado (mais uma vez com o botao direito do rato) e escolhemos colar especial.

  • Quando nos apareceu o menu do "colar especial" assinalamos "colar ligação" e clickamos em "OK"

Calculámos os totais de entradas e saidas através de tabela dinâmica, da seguinte forma:

  • Seleccionámos as colunas de SAIDAS e ENTRADAS (seleccção dados pra tabela)

  • Fomos ao Menu Dados---->Assistente de Dados----> Iniciar:

  • Em Selecionar Origem escolhemos "Selecção actual"

Aqui encontrámos, de facto a grande diferença entre o CALC e o Excel, pois neste ponto, aparecer-nos ia um menu onde poderíamos escolher não só o esquema da tabela dinâmica, que nos aparece no CALC, como a suas opções e, entre elas, a opção de “actualizar ao abrir” que, por mais que procurássemos , não encontrámos no CALC.

  • Apareceu-nos o esquema da Tabela Dinâmica com os dados seleccionados (Saidas e Entradas) do lado direito

  • Arrastamos Saidas e Entradas para dentro de "Campos de Dados"

  • em "Mais" escolhemos o esquema da tabela e o local onde queríamos os resultados, ficando assim


Clickando com o botão direito do rato em cima da tabela dinâmica, e escolhendo “Actualizar” a tabela dinâmica actualiza-se

Depois de calculados os totais de entradas e saídas, pela sua diferença, calculamos os saldos.

Uma vez calculados os saldos em cada folha, procedemos à sua ligação com a folha dos saldos da mesma forma que procederamos á ligação da primeira folha com a folha de cada rúbrica, assim:

Na folha dos saldos procedemos então ao cálculo das receitas e das despesas.


Tudo isto para constactarmos que nos saímos perfeitamente no CALC em tudo o que faríamos no Excel, excepto no fazermos com que as tabelas dinamicas se actualizassem automaticamente, o que parecendo que não, é de uma grande importância, pois, suponhamos o que faria a minha mulher que não percebe nada de folhas de cálculo ( o que por acaso não acontece, mas como se trata de suponhamos) para ver qual era a nossa situação financeira em determinada altura?

Pois abriria a folha de cálculo e iria logo para a folha dos saldos que poderia não estar certa, bastando, para tanto, que eu, ao registar os últimos movimentos, me esquecesse de ter actualizado todas as tabelas dinâmicas.


PS: Se alguem quiser o exemplo construído é so deixar aqui o mail que enviarei directamente.