Você está na página 1de 173

Manual de thinTemplates

Construção de Programas
Novembro/2009
Copyright © 2009 TOTVS S.A. Todos os direitos reservados.
Nenhuma parte deste documento pode ser copiada, reproduzida, traduzida ou
transmitida por qualquer meio eletrônico ou mecânico, na sua totalidade ou em
parte, sem a prévia autorização escrita da TOTVS S.A., que reserva-se o
direito de efetuar alterações sem aviso prévio. A TOTVS S.A não assume
nenhuma responsabilidade pelas conseqüências de quaisquer erros ou
inexatidões que possam aparecer neste documento.
TOTVS S.A.
Av. Santos Dumont, 831, Joinville, SC, CEP 89.222-900
i

Índice

CAPÍTULO 1 Conceitos ............................................................................. 1

CAPÍTULO 2 Construindo o thinMaintenance ........................................ 3


Tarefas ........................................................................................................... 4
Considerações .............................................................................................. 17
CAPÍTULO 3 Construindo o thinMasterDetail ...................................... 19
Tarefas ......................................................................................................... 20
Considerações .............................................................................................. 39
CAPÍTULO 4 Construindo o thinMaintenanceNoNavigation ............... 41
Tarefas ......................................................................................................... 42
Considerações .............................................................................................. 52
CAPÍTULO 5 Construindo o thinZoom .................................................. 55
Tarefas ......................................................................................................... 56
CAPÍTULO 6 Construindo o thinWindow .............................................. 73
Tarefas ......................................................................................................... 74
Considerações .............................................................................................. 78
CAPÍTULO 7 Construindo o thinReport ................................................ 79
Tarefas ......................................................................................................... 80
Considerações ............................................................................................ 100
Como migrar relatórios antigos para RTF ................................................. 101
CAPÍTULO 8 Construindo o thinFormation ........................................ 109
Tarefas ....................................................................................................... 110
Considerações ............................................................................................ 124
ii

CAPÍTULO 9 Construindo o thinFormationNoNavigation ................. 126


Tarefas ....................................................................................................... 127
Considerações ............................................................................................ 137
CAPÍTULO 10 Técnicas ........................................................................... 139
Override de métodos .................................................................................. 139
Pesquisa de chaves estrangeiras ................................................................. 141
Pesquisa de chaves estrangeiras em Browses ............................................ 142
Pesquisa de chaves estrangeiras com SmartZoom ..................................... 144
Referências para chaves estrangeiras ......................................................... 146
Referências para chaves estrangeiras em Browses .................................... 150
Campos indicadores (combo-box, selection-list ou radio-set) ................... 154
Exibir Mensagens de Erro Ocorridas ......................................................... 156
Reposicionamento Automático do Browser de Zoom ............................... 158
Utilização de OCX ..................................................................................... 159
Override de eventos do browse no template MasterDetail e Zoom ........... 161
Recursos avançados do thinFolder............................................................. 162
Correção do tab-order no ThinReport ........................................................ 165
Como desenvolver para o Datasul 10 ........................................................ 167
1

CAPÍTULO 1

Conceitos

Introdução O objetivo deste documento é apresentar os métodos para codificação de


programas, utilizando os thinTemplates, a fim de que possam utilizar em
conjunto com os DBOs (Datasul Business Objects).
Neste manual, descreve-se o que são os thinTemplates, como construir etc.

A arquitetura dos thinTemplates foi definida com o objetivo de separar a


Definição
camada de lógica de apresentação (interface com o usuário) da camada de
lógica da aplicação (regras de negócio). Assim, toda a lógica de apresentação
torna-se independente da lógica de aplicação.
Os thinTemplates, somente executam as regras de negócio contidas nos DBOs.
E, assim, podem ser utilizados sem conexão com os bancos de dados.

Comportamento
Interface Lógica Dados

thinTemplates DBOs Databases

Características As características destes são:


 independência de banco de dados, pois a comunicação é feita pelo DBO;
2

 alta performance, podendo ainda o DBO ser executado através do recurso


de RPC (Remote Procedure Call);
 normalmente utiliza temp-tables para troca de informações com o DBO;
 normalmente são executados de forma persistente;
 facilidade de customização, pois toda a lógica de interface encontra-se em
1 (um) único programa (não utiliza o recurso de Smart Objects: Broker,
SmartWindow, SmartQuery, SmartViewer, SmartBrowse, SmartFolder
etc);
3

CAPÍTULO 2

Construindo o thinMaintenance

Introdução Neste estão informações para que o desenvolvedor possa construir um


programa baseado no template thinMaintenance.
A seguir está um exemplo de um programa construído com o template
thinMaintenance:

Vale ressaltar que toda a exemplificação será feita utilizando o banco de dados
Sports.

Características As características deste são:


4

 normalmente todas as funções, com exceção da Pesquisa, são realizadas na


própria tela base do programa;
 pode ser utilizado tanto para consulta como para manutenção, usando para
isto uma ou mais páginas;
 o gerenciamento das páginas do folder é feito pelo programa
objects/thinFolder.w;

 faz uso do sistema de tradução de .R, bastando para tanto identificar as


strings que não devem ser traduzidas com :U (Exemplo: "CHOOSE":U).
Observação: O identificador :T no início de alguns comentários, é usado para a
tradução dos fontes dos templates para outros idiomas. Este identificador não
afeta em nada a funcionalidade do programa.

Triggers de botões  Trigger de Choose para o botão btSearch :


padrão
Parâmetro Descrição
ProgramZoom Nome do programa a ser executado para realizar a
pesquisa de registros

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btSearch IN FRAME fPage0 /* Search */
OR CHOOSE OF MENU-ITEM miSearch IN MENU mbMain DO:
{method/ZoomReposition.i &ProgramZoom="C:/Programs/Zoom.w "}
END.

Tarefas
A seguir é apresentada a lista de tarefas para desenvolvimento do programa.

Preprocessors Inicialmente devem ser definidos os valores dos preprocessors padrão do


programa.
A seguir existe uma tabela que possui o nome dos preprocessors padrão e suas
descrições:
CAPÍTULO 2 Construindo o thinMaintenance 5

Preprocessor Descrição
Program Nome do programa - Formato (XX9999)
Version Versão do programa – Formato (9.99.99.999)
Folder O valor YES indica que o programa terá folder
InitialPage Indica em qual página o programa irá iniciar
FolderLabels Descrição de cada uma das páginas do folder
First O valor YES indica que o programa possui a função de
posicionamento no primeiro registro
Prev O valor YES indica que o programa possui a função de
posicionamento no registro anterior
Next O valor YES indica que o programa possui a função de
posicionamento no próximo registro
Last O valor YES indica que o programa possui a função de
posicionamento no último registro
GoTo O valor YES indica que o programa possui a função de
Vá Para
Search O valor YES indica que o programa possui a função de
Pesquisa
Add O valor YES indica que o programa possui a função de
inclusão
Copy O valor YES indica que o programa possui a função de
cópia
Update O valor YES indica que o programa possui a função de
alteração
Delete O valor YES indica que o programa possui a função de
eliminação
Undo O valor YES indica que o programa possui a função de
desfazer
Cancel O valor YES indica que o programa possui a função de
cancelamento
Save O valor YES indica que o programa possui a função de
gravação
ttTable Nome da temp-table utilizada para comunicação com o
DBO
HDBOTable Nome da variável que contém o handle do DBO
DBOTable Nome da tabela principal do DBO
page0KeyFields Nome dos campos chaves que estão na frame fPage0
PageNFields Nome dos campos que estão nas frames fPageN, N
indica o número da página, podendo variar de 0 até 8
EnableMaxButton Caso definido com o valor YES, o template mantém o
botão de maximizar da janela habilitado. O padrão dos
6

Preprocessor Descrição
templates é manter este botão desabilitado.

Observação O preprocessor Program refere-se ao nome com o qual o programa


está ou será cadastrado no menu.

Exemplo de código com o preenchimento dos preprocessadores:


&GLOBAL-DEFINE Program thinMaintenance
&GLOBAL-DEFINE Version 1.00.00.000

&GLOBAL-DEFINE Folder YES


&GLOBAL-DEFINE InitialPage 1

&GLOBAL-DEFINE FolderLabels Personal,Financial

&GLOBAL-DEFINE First YES


&GLOBAL-DEFINE Prev YES
&GLOBAL-DEFINE Next YES
&GLOBAL-DEFINE Last YES
&GLOBAL-DEFINE GoTo YES
&GLOBAL-DEFINE Search YES

&GLOBAL-DEFINE Add YES


&GLOBAL-DEFINE Copy YES
&GLOBAL-DEFINE Update YES
&GLOBAL-DEFINE Delete YES
&GLOBAL-DEFINE Undo YES
&GLOBAL-DEFINE Cancel YES
&GLOBAL-DEFINE Save YES

&GLOBAL-DEFINE ttTable ttCustomer


&GLOBAL-DEFINE hDBOTable hDBOCustomer
&GLOBAL-DEFINE DBOTable Customer

&GLOBAL-DEFINE page0KeyFields ttCustomer.Cust-Num


&GLOBAL-DEFINE page0Fields ttCustomer.Name
&GLOBAL-DEFINE page1Fields ttCustomer.Address ~
ttCustomer.Address2 ~
ttCustomer.City ~
ttCustomer.State ~
ttCustomer.Country
&GLOBAL-DEFINE page2Fields ttCustomer.Credit-Limit ~
ttCustomer.Balance ~
ttCustomer.Sales-Rep

Quando o desenvolvedor optar por retirar uma ou mais funções do programa,


deve-se alterar o conteúdo do preprocessor correspondente e, além disso,
eliminar os botões, menus etc, relacionados à função eliminada.
CAPÍTULO 2 Construindo o thinMaintenance 7

Para retirar os botões de Consultas Relacionadas e Relatórios Relacionados, o


desenvolvedor deve incluir o preprocessor padrão referente ao botão que
deseja retirar.
&GLOBAL-DEFINE ExcludeBtQueryJoins YES
&GLOBAL-DEFINE ExcludeBtReportsJoins YES

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se criar um
preprocessador chamado DBOVersion, na sessão Definitions, com o valor
1.1. A seguir modelo de sua definição:
&GLOBAL-DEFINE DBOVersion 1.1

Temp-Table de Criar a temp-table que é utilizada para realizar a comunicação com o DBO. E
Comunicação deve estar disponível para inclusão de campos em tela.
Para tanto deve-se utilizar o menu Tools | Procedure Settings, botão:

A tela a seguir é aberta, nesta deve criar-se a temp-table e definir um campo


chamado r-Rowid. E ainda, a definição desta temp-table deve ser idêntica a
definição da temp-table do DBO.
8

Instância do DBO A criação da instância do DBO deve ser feita manualmente, utilizando ou não
o recurso de RPC. Logo após deve-se definir as restrições iniciais e a abertura
da query caso necessário.
A instância do DBO é feita no método initializeDBOs.
A seguir existe uma tabela que possui o nome dos parâmetros e suas
descrições:
Parâmetro Descrição
DBOProgram Nome físico do programa DBO
Description Identifica o nome da constraint a ser utilizada
inicialmente
Query Identifica o nome da query a ser utilizada para realizar a
abertura inicial do DBO
CAPÍTULO 2 Construindo o thinMaintenance 9

Exemplo de código com o preenchimento dos parâmetros:


PROCEDURE initializeDBOs:
/*-----------------------------------------------------------------
Purpose: Inicializa DBOs
Parameters:
Notes:
-----------------------------------------------------------------*/

/*--- Verifica se o DBO já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOTable}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOCustomer.p YES}
{btb/btb008za.i2 C:/Programs/DBOCustomer.p '' {&hDBOTable}}
END.

/*--- Abre query CustNum do DBO ---*/


RUN openQueryStatic IN {&hDBOTable} (INPUT "CustNum":U) NO-ERROR.

RETURN "OK":U.
END PROCEDURE.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
métodos disponíveis nesta versão. Além disso, o desenvolvedor deve usar o
preprocessador DBOVersion a fim de permitir fácil migração do programa
para o DBO 2.0.
A seguir modelo de instância de BO 1.1, preparado para migração:
PROCEDURE initializeDBOs:
/*-----------------------------------------------------------------
Purpose: Inicializa DBOs
Parameters:
Notes:
-----------------------------------------------------------------*/

/*--- Verifica se o DBO já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOTable}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOCustomer.p YES}
{btb/btb008za.i2 C:/Programs/DBOCustomer.p '' {&hDBOTable}}
END.

/*--- Abre query CustNum ou 1 do DBO ---*/


&IF DEFINED(DBOVersion) <> 0 &THEN
RUN openQuery IN {&hDBOTable} (INPUT 1) NO-ERROR.
&ELSE
RUN openQueryStatic IN {&hDBOTable} (INPUT "CustNum":U) NO-
ERROR.
&ENDIF

RETURN "OK":U.
END PROCEDURE.
10

Páginas do folder O template, inicialmente, possui a definição de 2 (duas) páginas. O


desenvolvedor pode retirá-las, a fim de manter somente a página principal, ou
acrescentar novas páginas, até o limite máximo de 8 (oito) páginas.
No entanto, se o programa não possuir as páginas fPage0 e fPage1, não é
possível inicializar o folder em tempo de execução (EPC). Por isso, aconselha-
se que, mesmo não sendo necessário o folder no momento do desenvolvimento
do programa, o programador conserve as páginas fPage0 e fPage1, alterando
apenas o pré-procesador Folder NO.
A frame principal (fPage0) somente pode ter sua altura alterada, o restante
das propriedades deve ser mantido. A altura deste é definida da forma a seguir:
 posicionamento da linha acrescido da altura dos frames das páginas.
Para cada página está relacionado um widget frame, possuindo a nomenclatura
fPage<PageNumber>. Para estes frames deve ser definida o fonte 1 e
seguido as regra de posicionamento e tamanho, descrita a seguir:
 devem estar posicionados na coluna 3.50;
 a linha na qual devem estar posicionados fica a 1.45 abaixo do último
widget da frame principal (fPage0);
 a largura não deve ser alterada (84.43);
 a altura é definida através da quantidade de widgets em linha acrescido de
0.25.
A imagem a seguir exibe como fica a janela do programa durante sua
construção:
CAPÍTULO 2 Construindo o thinMaintenance 11

Vale ressaltar que os labels das páginas não aparecem em tempo de


desenvolvimento, pois são criados durante a execução do programa. Por isso
faz-se necessário o espaço entre os frames das páginas e o último widget da
frame principal (fPage0).
Observação Para os campos do tipo fill-in’s, deve ser observado se o mesmo possue trigger
de "LEAVE"/"VALUE-CHANGED" e não tenha lupa como cursor do mouse ou um botão de
zoom na sua direita; ou possua trigger de "ENTRY". Caso o fill-in se encaixe em uma das
opções acima, deve ser efetuado o registro para o WebEnabler, conforme técnica Como registrar
campo do tipo Fill-in para o WebEnabler do Manual de Padrões.
O WebEnabler já registra automaticamente o evento de "LEAVE" para TODOS os fill-ins que
possuírem a lupa como cursor do mouse, ou que possuírem um botão de zoom na sua direita.
Portanto não é necessário efetuar o registro para esses fill-ins.

Disposição dos Quando for necessário fazer a inclusão de widgets (sejam campos ou widgets
widgets nas comuns) deve-se primeiramente selecionar o frame de trabalho. Para tanto usa-
páginas se o botão:

A tela a seguir é aberta, nesta deve selecionar-se a frame desejada e clicar-se


no botão que está indicado:
12

Após a seleção do frame de trabalho, deve-se fazer a inclusão dos widgets.


Para os widgets da temp-table de comunicação deve-se utilizar o botão a
seguir:

A tela a seguir é aberta, nesta deve selecionar-se o item Temp-Tables, a temp-


table desejada e logo após os campos a serem inclusos na frame de trabalho:
CAPÍTULO 2 Construindo o thinMaintenance 13

Após a inclusão dos campos, ou widgets comuns, devem ser feitas algumas
alterações de suas propriedades. Estas são descritas a seguir:
 devem estar dispostos em linha, e caso necessário em colunas;
 para widgets do tipo fill-in, sua altura deve ser de 0.88;
 para widgets dos tipos combo-box, suas alturas devem ser de 1.00;
 para widgets dos tipos editores ou list-box ou radio-set, suas alturas devem
ser definidas pelo próprio desenvolvedor;
 para os widgets que fazem parte do índice único e suas descrições, devem
ser dispostos no retângulo rtKeys;
 a linha na qual os widgets que estão na primeira linha do retângulo rtKeys,
deve ser 2.83; os demais devem estar a distância de 1.00 do widget
anterior;
 a linha na qual os widgets que estão na primeira linha dos frames das
páginas, deve ser 1.17; os demais devem estar a distância de 1.00 do
widget anterior.

Método O método goToRecord é responsável pela função de Vá Para, disparada pelo


goToRecord botão btGoTo e pelo menu miGoTo.
O código do método está predefinido, mas necessita de pequenas alterações.
Tais como a definição dos campos a serem utilizados, tamanho da frame etc.
14

A seguir existe uma tabela que possui o nome dos parâmetros e suas
descrições:
Parâmetro Descrição
<c|d|i> Indica o tipo de variável (c = character, d = decimal, i =
integer)
<campo N> nomes dos campos a serem inclusos na frame de Vá
Para
<Tabela> nome da tabela a ser utilizado para definir o título da
frame de Vá Para

Exemplo de código com o preenchimento dos parâmetros:


PROCEDURE goToRecord:
/*---------------------------------------------------------------------
Purpose: Exibe dialog de Vá Para
Parameters:
Notes:
---------------------------------------------------------------------*/

DEFINE BUTTON btGoToCancel AUTO-END-KEY


LABEL "&Cancelar"
SIZE 10 BY 1
BGCOLOR 8.

DEFINE BUTTON btGoToOK AUTO-GO


LABEL "&OK"
SIZE 10 BY 1
BGCOLOR 8.

DEFINE RECTANGLE rtGoToButton


EDGE-PIXELS 2 GRAPHIC-EDGE
SIZE 35 BY 1.42
BGCOLOR 7.

DEFINE VARIABLE rGoTo AS ROWID NO-UNDO.

DEFINE VARIABLE iCust-Num LIKE ttCustomer.Cust-Num NO-UNDO.

DEFINE FRAME fGoToRecord


iCust-Num AT ROW 1.21 COL 15 COLON-ALIGNED
btGoToOK AT ROW 2.63 COL 2.14
btGoToCancel AT ROW 2.63 COL 13
rtGoToButton AT ROW 2.38 COL 1
SPACE(0.28)
WITH VIEW-AS DIALOG-BOX KEEP-TAB-ORDER SIDE-LABELS NO-UNDERLINE
THREE-D SCROLLABLE FONT 1 TITLE "Vá Para Customer"
DEFAULT-BUTTON btGoToOK CANCEL-BUTTON btGoToCancel.

RUN utp/ut-trfrrp.p (input Frame fGoToRecord:Handle).


{utp/ut-liter.i "Vá_Para_<tabela>"}
ASSIGN FRAME fGoToRecord:TITLE = RETURN-VALUE.
CAPÍTULO 2 Construindo o thinMaintenance 15

ON "CHOOSE":U OF btGoToOK IN FRAME fGoToRecord DO:


ASSIGN iCustNum.

RUN goToKey IN {&hDBOTable} (INPUT iCustNum).


IF RETURN-VALUE = "NOK":U THEN DO:
RUN utp/ut-msgs.p (INPUT "SHOW":U, INPUT 2, INPUT "Customer").

RETURN NO-APPLY.
END.

/* Retorna rowid do registro corrente do DBO */


RUN getRowid IN {&hDBOTable} (OUTPUT rGoTo).

/* Reposiciona registro com base em um rowid */


RUN repositionRecord IN THIS-PROCEDURE (INPUT rGoTo).

APPLY "GO":U TO FRAME fGoToRecord.


END.

ENABLE iCust-Num btGoToOK btGoToCancel


WITH FRAME fGoToRecord.

WAIT-FOR "GO":U OF FRAME fGoToRecord.


END PROCEDURE.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
métodos disponíveis nesta versão. Além disso, o desenvolvedor deve usar o
preprocessador DBOVersion a fim de permitir fácil migração do programa
para o DBO 2.0.
A seguir modelo do método goToRecord, preparado para migração:
PROCEDURE goToRecord:
/*---------------------------------------------------------------------
Purpose: Exibe dialog de Vá Para
Parameters:
Notes:
---------------------------------------------------------------------*/

DEFINE BUTTON btGoToCancel AUTO-END-KEY


LABEL "&Cancelar"
SIZE 10 BY 1
BGCOLOR 8.

DEFINE BUTTON btGoToOK AUTO-GO


LABEL "&OK"
SIZE 10 BY 1
BGCOLOR 8.

DEFINE RECTANGLE rtGoToButton


EDGE-PIXELS 2 GRAPHIC-EDGE
16

SIZE 35 BY 1.42
BGCOLOR 7.

DEFINE VARIABLE cStatus AS CHARACTER NO-UNDO.

DEFINE VARIABLE rGoTo AS ROWID NO-UNDO.

DEFINE VARIABLE iCust-Num LIKE ttCustomer.Cust-Num NO-UNDO.

DEFINE FRAME fGoToRecord


iCust-Num AT ROW 1.21 COL 15 COLON-ALIGNED
btGoToOK AT ROW 2.63 COL 2.14
btGoToCancel AT ROW 2.63 COL 13
rtGoToButton AT ROW 2.38 COL 1
SPACE(0.28)
WITH VIEW-AS DIALOG-BOX KEEP-TAB-ORDER SIDE-LABELS NO-UNDERLINE
THREE-D SCROLLABLE FONT 1 TITLE "Vá Para Customer"
DEFAULT-BUTTON btGoToOK CANCEL-BUTTON btGoToCancel.

RUN utp/ut-trfrrp.p (input Frame fGoToRecord:Handle).


{utp/ut-liter.i "Vá_Para_<tabela>"}
ASSIGN FRAME fGoToRecord:TITLE = RETURN-VALUE.

ON "CHOOSE":U OF btGoToOK IN FRAME fGoToRecord DO:


ASSIGN iCustNum.

&IF DEFINED(DBOVersion) <> 0 &THEN


RUN findCust-Num IN {&hDBOTable} (INPUT iCustNum,
OUTPUT cStatus).
IF cStatus <> "":U THEN DO:
RUN utp/ut-msgs.p (INPUT "SHOW":U,
INPUT 2,
INPUT "Customer").

RETURN NO-APPLY.
END.
&ELSE
RUN goToKey IN {&hDBOTable} (INPUT iCustNum).
IF RETURN-VALUE = "NOK":U THEN DO:
RUN utp/ut-msgs.p (INPUT "SHOW":U,
INPUT 2,
INPUT "Customer":U).

RETURN NO-APPLY.
END.
&ENDIF

/* Retorna rowid do registro corrente do DBO */


RUN getRowid IN {&hDBOTable} (OUTPUT rGoTo).

/* Reposiciona registro com base em um rowid */


RUN repositionRecord IN THIS-PROCEDURE (INPUT rGoTo).

APPLY "GO":U TO FRAME fGoToRecord.


END.
CAPÍTULO 2 Construindo o thinMaintenance 17

ENABLE iCust-Num btGoToOK btGoToCancel


WITH FRAME fGoToRecord.

WAIT-FOR "GO":U OF FRAME fGoToRecord.


END PROCEDURE.

Considerações
Quando é construído um programa utilizando o template thinMaintenance
necessita-se realizar a implementação de lógicas auxiliares, tais como:
 programa de pesquisa de chave estrangeira;
 referência para campos de chave estrangeira.
Para tanto, deve-se utilizar o capítulo de Técnicas.

Além disso, necessita-se realizar a construção separadamente, em muitas


situações, do programa a seguir:
 programa de pesquisa.
Para a construção deste programa deve ser utilizado o capítulo:
 Construindo o thinZoom.

Caso o pré-processador EnableMaxButton seja definido, é necessário codificar


o funcionamento do evento de Maximizar, uma vez que o Progress apenas
aumenta o tamanho da janela, e não atualiza os tamanhos e posições dos
campos.
19

CAPÍTULO 3

Construindo o thinMasterDetail

Introdução Neste estão informações para que o desenvolvedor possa construir um


programa baseado no template thinMasterDetail.
A seguir está um exemplo de um programa construído com o template
thinMasterDetail:
20

Vale ressaltar que toda a exemplificação será feita utilizando o banco de dados
Sports.

Características As características deste são:


 algumas das funções são realizadas na própria tela base do programa;
 pode ser utilizado tanto para consulta como para manutenção, usando para
isto uma ou mais páginas;
 cada uma das páginas é utiliza para identificar os diferentes filhos
associados a tabela principal do programa;
 o gerenciamento das páginas do folder é feito pelo programa
objects/thinFolder.w;

 faz uso do sistema de tradução de .R, bastando para tanto identificar as


strings que não devem ser traduzidas com :U (Exemplo: "CHOOSE":U).
Observação: O identificador :T no início de alguns comentários, é usado para a
tradução dos fontes dos templates para outros idiomas. Este identificador não
afeta em nada a funcionalidade do programa.

Tarefas
A seguir é apresentada a lista de tarefas para desenvolvimento do programa.

Preprocessors Inicialmente devem ser definidos os valores dos preprocessors padrão do


programa.
Preprocessor Descrição
Program Nome do programa – Formato (XX9999)
Version Versão do programa – Formato (9.99.99.999)
Folder O valor YES indica que o programa terá folder
InitialPage Indica em qual página o programa irá iniciar
FolderLabels Descrição de cada uma das páginas do folder
First O valor YES indica que o programa possui a função de
posicionamento no primeiro registro
Prev O valor YES indica que o programa possui a função de
posicionamento no registro anterior
CAPÍTULO 3 Construindo o thinMasterDetail 21

Preprocessor Descrição
Next O valor YES indica que o programa possui a função de
posicionamento no próximo registro
Last O valor YES indica que o programa possui a função de
posicionamento no último registro
GoTo O valor YES indica que o programa possui a função de
Vá Para
Search O valor YES indica que o programa possui a função de
Pesquisa
AddParent O valor YES indica que o programa possui a função de
inclusão de pai
CopyParent O valor YES indica que o programa possui a função de
cópia de pai
UpdateParent O valor YES indica que o programa possui a função de
alteração de pai
DeleteParent O valor YES indica que o programa possui a função de
eliminação de pai
AddSonN O valor YES indica que o programa possui a função de
inclusão de filho N, N indica o número da página,
podendo variar de 1 até 8
CopySonN O valor YES indica que o programa possui a função de
cópia de filho N, N indica o número da página,
podendo variar de 1 até 8
UpdateSonN O valor YES indica que o programa possui a função de
alteração de filho N, N indica o número da página,
podendo variar de 1 até 8
DeleteSonN O valor YES indica que o programa possui a função de
eliminação de filho N, N indica o número da página,
podendo variar de 1 até 8
ttParent Nome da temp-table pai (principal) utilizada para
comunicação com o DBO
hDBOParent Nome da variável que contém o handle do DBO pai
(principal)
DBOParent Nome da tabela principal do DBO pai (principal)
DBOParentDestroy Valor ou nome da variável lógica que contém flag
indicando se o DBO pai deve ser destruído ao final da
execução do programa, o valor lógica YES indica
destruição
ttSonN Nome da temp-table filha N (secundária) utilizada para
comunicação com o DBO, N indica o número da
página, podendo variar de 1 até 8
22

Preprocessor Descrição
hDBOSonN Nome da variável que contém o handle do DBO filho N
(secundário), N indica o número da página, podendo
variar de 1 até 8
DBOSonN Nome da tabela principal do DBO filho N (secundário),
N indica o número da página, podendo variar de 1 até
8
DBOSonNDestroy Valor ou nome da variável lógica que contém flag
indicando se o DBO filho N deve ser destruído ao final
da execução do programa, o valor lógica YES indica
destruição
page0Fields Nome dos campos da temp-table pai (principal) que
estão na frame fPage0
pageNBrowse Nome do browser que está na frame fPageN, N indica
o número da página, podendo variar de 1 até 8
EnableMaxButton Caso definido com o valor YES, o template mantém o
botão de maximizar da janela habilitado. O padrão dos
templates é manter este botão desabilitado.

Observação O preprocessor Program refere-se ao nome com o qual o programa


está ou será cadastrado no menu.

Exemplo de código com o preenchimento dos preprocessadores:


&GLOBAL-DEFINE Program thinMasterDetail
&GLOBAL-DEFINE Version 1.00.00.000

&GLOBAL-DEFINE Folder YES


&GLOBAL-DEFINE InitialPage 1

&GLOBAL-DEFINE FolderLabels Order

&GLOBAL-DEFINE First YES


&GLOBAL-DEFINE Prev YES
&GLOBAL-DEFINE Next YES
&GLOBAL-DEFINE Last YES
&GLOBAL-DEFINE GoTo YES
&GLOBAL-DEFINE Search YES

&GLOBAL-DEFINE AddParent YES


&GLOBAL-DEFINE CopyParent YES
&GLOBAL-DEFINE UpdateParent YES
&GLOBAL-DEFINE DeleteParent YES

&GLOBAL-DEFINE AddSon1 YES


&GLOBAL-DEFINE CopySon1 YES
CAPÍTULO 3 Construindo o thinMasterDetail 23

&GLOBAL-DEFINE UpdateSon1 YES


&GLOBAL-DEFINE DeleteSon1 YES

&GLOBAL-DEFINE ttParent ttCustomer


&GLOBAL-DEFINE hDBOParent hDBOCustomer
&GLOBAL-DEFINE DBOParentTable Customer
&GLOBAL-DEFINE DBOParentDestroy YES

&GLOBAL-DEFINE ttSon1 ttOrder


&GLOBAL-DEFINE hDBOSon1 hDBOOrder
&GLOBAL-DEFINE DBOSon1Table Order
&GLOBAL-DEFINE DBOSon1Destroy YES

&GLOBAL-DEFINE page0Fields ttCustomer.Cust-Num ~


ttCustomer.Name
&GLOBAL-DEFINE page1Browse brSon1

Quando o programa for utilizado para consulta, deve-se utilizar os


preprocessors padrão descritos anteriormente e acrescentar o preprocessor
padrão a seguir:
Preprocessor Descrição
DetailSonN O valor YES indica que o programa possui a função de
detalhe de filho N, N indica o número da página,
podendo variar de 1 até 8

Para definir o número de registros que devem ser retornados para o browse,
deve-se utilizar os preprocessors padrão descritos anteriormente e acrescentar
o preprocessor padrão a seguir:
Preprocessor Descrição
NumRowsReturned Número de registros que devem ser retornados no
browse

Observação O preprocessor Program refere-se ao nome com o qual o programa


está ou será cadastrado no menu.

Exemplo de código com o preenchimento dos preprocessadores:


&GLOBAL-DEFINE Program thinMasterDetail
&GLOBAL-DEFINE Version 1.00.00.000

&GLOBAL-DEFINE Folder YES


&GLOBAL-DEFINE InitialPage 1

&GLOBAL-DEFINE FolderLabels Order


24

&GLOBAL-DEFINE First YES


&GLOBAL-DEFINE Prev YES
&GLOBAL-DEFINE Next YES
&GLOBAL-DEFINE Last YES
&GLOBAL-DEFINE GoTo YES
&GLOBAL-DEFINE Search YES

&GLOBAL-DEFINE AddParent NO
&GLOBAL-DEFINE CopyParent NO
&GLOBAL-DEFINE UpdateParent NO
&GLOBAL-DEFINE DeleteParent NO

&GLOBAL-DEFINE AddSon1 NO
&GLOBAL-DEFINE CopySon1 NO
&GLOBAL-DEFINE UpdateSon1 NO
&GLOBAL-DEFINE DeleteSon1 NO
&GLOBAL-DEFINE DetailSon1 YES

&GLOBAL-DEFINE ttParent ttCustomer


&GLOBAL-DEFINE hDBOParent hDBOCustomer
&GLOBAL-DEFINE DBOParentTable Customer
&GLOBAL-DEFINE DBOParentDestroy YES

&GLOBAL-DEFINE ttSon1 ttOrder


&GLOBAL-DEFINE hDBOSon1 hDBOOrder
&GLOBAL-DEFINE DBOSon1Table Order
&GLOBAL-DEFINE DBOSon1Destroy YES

&GLOBAL-DEFINE page0Fields ttCustomer.Cust-Num ~


ttCustomer.Name
&GLOBAL-DEFINE page1Browse brSon1
&GLOBAL-DEFINE NumRowsReturned 25

Quando o desenvolvedor optar por retirar uma ou mais funções do programa,


deve-se alterar o conteúdo do preprocessor correspondente e, além disso,
eliminar os botões, menus etc, relacionados à função eliminada.
Para retirar os botões de Consultas Relacionadas e Relatórios Relacionados, o
desenvolvedor deve incluir o preprocessor padrão referente ao botão que
deseja retirar.
&GLOBAL-DEFINE ExcludeBtQueryJoins YES
&GLOBAL-DEFINE ExcludeBtReportsJoins YES

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se criar um
preprocessador chamado DBOVersion, na sessão Definitions, com o valor
1.1. A seguir modelo de sua definição:
&GLOBAL-DEFINE DBOVersion 1.1
CAPÍTULO 3 Construindo o thinMasterDetail 25

Temp-Table de Criar as temp-tables que são utilizadas para realizar a comunicação com os
Comunicação DBOs. E devem estar disponíveis para inclusão de campos em tela.
Para tanto deve-se utilizar o menu Tools | Procedure Settings, botão:

A tela a seguir é aberta, nesta devem criar-se as temp-tables e definir um


campo chamado r-Rowid. E ainda, as definições destas temp-tables devem
ser idênticas as definições das temp-tables dos DBOs.

Instâncias do As criações das instâncias do DBOs (DBO Pai e DBOs Filho) devem ser feitas
DBOs manualmente, utilizando ou não o recurso de RPC. Logo após deve-se definir
as restrições iniciais e a abertura da query do DBO Pai, caso necessário.
26

As instâncias dos DBOs são feitas no método initializeDBOs.


A seguir existe uma tabela que possui o nome dos parâmetros e suas
descrições:

Parâmetro Descrição
DBOParentProgram Nome físico do programa DBO pai (principal)
Description Identifica o nome da constraint a ser utilizada
inicialmente para o DBO pai (principal)
Query Identifica o nome da query a ser utilizada para realizar
a abertura inicial do DBO pai
DBOProgramSonN Nome físico do programa DBO filho N, N indica o
número da página, podendo variar de 1 até 8

Exemplo de código com o preenchimento dos parâmetros:


PROCEDURE initializeDBOs:
/*-----------------------------------------------------------------
Purpose: Inicializa DBOs
Parameters:
Notes:
-----------------------------------------------------------------*/

/*--- Verifica se o DBO já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOParent}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOCustomer.p YES}
{btb/btb008za.i2 C:/Programs/DBOCustomer.p '' {&hDBOParent}}
END.

/*--- Abre query CustNum do DBO ---*/


RUN openQueryStatic IN {&hDBOParent} (INPUT "CustNum":U) NO-ERROR.

/*--- Verifica se o DBO já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOSon1}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOOrder.p YES}
{btb/btb008za.i2 C:/Programs/DBOOrder.p '' {&hDBOSon1}}
END.

RETURN "OK":U.
END PROCEDURE.

A associação entre o DBO Pai e os DBOs Filho é vista posteriormente.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
métodos disponíveis nesta versão. Além disso, o desenvolvedor deve usar o
CAPÍTULO 3 Construindo o thinMasterDetail 27

preprocessador DBOVersion a fim de permitir fácil migração do programa


para o DBO 2.0.
A seguir modelo de instância de BO 1.1, preparado para migração:
PROCEDURE initializeDBOs:
/*-----------------------------------------------------------------
Purpose: Inicializa DBOs
Parameters:
Notes:
-----------------------------------------------------------------*/

/*--- Verifica se o DBO já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOParent}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOCustomer.p YES}
{btb/btb008za.i2 C:/Programs/DBOCustomer.p '' {&hDBOParent}}
END.

/*--- Abre query CustNum ou 1 do DBO ---*/


&IF DEFINED(DBOVersion) <> 0 &THEN
RUN openQuery IN {&hDBOParent} (INPUT 1) NO-ERROR.
&ELSE
RUN openQueryStatic IN {&hDBOParent} (INPUT "CustNum":U) NO-
ERROR.
&ENDIF

/*--- Verifica se o DBO já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOSon1}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOOrder.p YES}
{btb/btb008za.i2 C:/Programs/DBOOrder.p '' {&hDBOSon1}}
END.

RETURN "OK":U.
END PROCEDURE.

Páginas do folder O template, inicialmente, possui a definição de 2 (duas) páginas. Mas o


desenvolvedor pode manter somente uma página, ou acrescentar novas
páginas, até o limite máximo de 8 (oito) páginas.
A frame principal (fPage0) somente pode ter sua altura alterada, o restante
das propriedades deve ser mantido. A altura deste é definida da forma a seguir:
 posicionamento da linha acrescido da altura dos frames das páginas.
Para cada página está relacionado um widget frame, possuindo a nomenclatura
fPage<PageNumber>. Para estes frames deve ser definida o fonte 1 e
seguido as regra de posicionamento e tamanho, descrita a seguir:
 devem estar posicionados na coluna 3.50;
28

 a linha na qual devem estar posicionados fica a 1.45 abaixo do último


widget da frame principal (fPage0);
 a largura não deve ser alterada (84.43);
 a altura, preferencialmente, deve ser mantida (9.46).
A imagem a seguir exibe como fica a janela do programa durante sua
construção:

Vale ressaltar que os labels das páginas não aparecem em tempo de


desenvolvimento, pois são criados durante a execução do programa. Por isso
faz-se necessário o espaço entre os frames das páginas e o último widget da
frame principal (fPage0).
Observação Para os campos do tipo fill-in’s, deve ser observado se o mesmo possue trigger
de "LEAVE"/"VALUE-CHANGED" e não tenha lupa como cursor do mouse ou um botão de
zoom na sua direita; ou possua trigger de "ENTRY". Caso o fill-in se encaixe em uma das
opções acima, deve ser efetuado o registro para o WebEnabler, conforme técnica Como registrar
campo do tipo Fill-in para o WebEnabler do Manual de Padrões.
O WebEnabler já registra automaticamente o evento de "LEAVE" para TODOS os fill-ins que
possuírem a lupa como cursor do mouse, ou que possuírem um botão de zoom na sua direita.
Portanto não é necessário efetuar o registro para esses fill-ins.
CAPÍTULO 3 Construindo o thinMasterDetail 29

Disposição dos Quando for necessário fazer a inclusão de widgets (sejam campos, widgets
widgets nas comuns ou browses) deve-se primeiramente selecionar o frame de trabalho.
páginas Para tanto usa-se o botão:

A tela a seguir é aberta, nesta deve selecionar-se a frame desejada e clicar-se


no botão que está indicado:

Após a seleção do frame de trabalho, deve-se fazer a inclusão dos widgets.


Para os widgets da temp-table de comunicação, que apresentam os valores do
DBO Pai, deve-se utilizar o botão a seguir:

A tela a seguir é aberta, nesta deve selecionar-se o item Temp-Tables, a temp-


table desejada e logo após os campos a serem inclusos na frame de trabalho:
30

Após a inclusão dos campos, ou widgets comuns, devem ser feitas algumas
alterações de suas propriedades. Estas são descritas a seguir:
 devem estar dispostos em linha, e caso necessário em colunas;
 para widgets do tipo fill-in, sua altura deve ser de 0.88;
 para widgets dos tipos combo-box, suas alturas devem ser de 1.00;
 para widgets dos tipos editores ou list-box ou radio-set, suas alturas devem
ser definidas pelo próprio desenvolvedor;
 para os widgets que fazem parte da temp-table Pai, devem ser dispostos no
retângulo rtParent;
 a linha na qual os widgets que estão na primeira linha do retângulo rtKeys,
deve ser 2.83; os demais devem estar a distância de 1.00 do widget
anterior.
Para os widgets que apresentam os valores dos DBOs Filho (browsers e botões
padrão que são Incluir, Copiar, Alterar, Eliminar e Detalhar), devem ser feitas
algumas alterações de suas propriedades. Estas são descritas a seguir:
 os nomes dos botões padrões devem seguir a nomenclatura:
btAddSon<PageNumber> (Incluir), btCopySon<PageNumber>
(Copiar), btUpdateSon<PageNumber> (Alterar),
btDeleteSon<PageNumber> (Eliminar) e
btDetailSon<PageNumber> (Detalhar);
 a largura dos botões padrão deve ser 10.00;
 a altura dos botões padrão deve ser 1.00;
CAPÍTULO 3 Construindo o thinMasterDetail 31

 a fonte dos browsers deve ser 2;


 a largura dos browsers deve ser 82.00;
 a altura dos browsers deve ser 8.00;
 a claúsula BY dos browsers deve ser a mesma utilizada na query do DBO
Filho.

Método O método openQueriesSon é responsável por realizar a ligação entre o DBO


openQueriesSon Pai e os DBOs Filho. Para tanto é feito o uso do include
masterdetail/OpenQueriesSon.i para atualizar os dados dos browsers
filho.
Uma das características deste include é a de trazer somente os 40 (quarenta)
primeiros registros associados aos browsers filho. Os próximos registros são
trazidos quando ocorrem os eventos de Cursor-Down, End, Off-End e
Page-Down, utilizando o mesmo método.
A seguir existe uma tabela que possui o nome dos parâmetros e suas
descrições:
Parâmetro Descrição
Parent Nome da tabela pai, utilizado para designar o método
linkTo<Parent>
Query Identifica o nome da query a ser utilizada para realizar
a abertura dos DBOs filho
PageNumber Número da página, utilizado para designar o nome de
alguns widgets, tais como btAddSon<PageNumber>,
btCopySon<PageNumber> etc

Exemplo de código com o preenchimento dos parâmetros:


PROCEDURE openQueriesSon:
/*------------------------------------------------------------------
Purpose: Atualiza browsers filhos
Parameters:
Notes:
------------------------------------------------------------------*/

{masterdetail/OpenQueriesSon.i &Parent="Customer"
&Query="OrderNum"
&PageNumber="1"}

RETURN "OK":U.
32

END PROCEDURE.

Quando o programa

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
novos parâmetros para o include masterdetail/OpenQueriesSon.i. A
seguir existe uma tabela que possui o nome dos novos parâmetros e suas
descrições:
Parâmetro Descrição
QueryConstraint número que identifica a query e a constraint, a ser
utilizado para passagem de parâmetro para o método
openQuery e para a definição do método
setConstraint{&QueryConstraint}
ConstraintParameters Parâmetros a serem utilizados para o método
setConstraint{&QueryConstraint}

Exemplo de código com o preenchimento dos novos parâmetros:


PROCEDURE openQueriesSon:
/*------------------------------------------------------------------
Purpose: Atualiza browsers filhos
Parameters:
Notes:
------------------------------------------------------------------*/

DEFINE VARIABLE iCust-Num AS INTEGER NO-UNDO.

IF AVAILABLE ttCustomer THEN


ASSIGN iCust-Num = ttCustomer.Cust-Num.
ELSE
ASSIGN iCust-Num = ?.

{masterdetail/OpenQueriesSon.i
&Parent="Customer"
&Query="OrderNum"
&PageNumber="1"
&QueryConstraint="2"
&ConstraintParameters="iCust-Num"}

RETURN "OK":U.
END PROCEDURE.

Triggers de botões
padrão
CAPÍTULO 3 Construindo o thinMasterDetail 33

Para os botões padrão, tanto aqueles que referenciam informações dos


registros pai e/ou filho, existem métodos ou includes padrão que precisam ser
definidos.
Inicialmente todos os botões já estão com valores prefixados, somente
necessitanto serem alterados em alguns casos.
A seguir existe uma tabela que possui a identificação das triggers, dos
parâmetros e suas descrições:
 Trigger de Choose para o botão btAdd:
Parâmetro Descrição
ProgramName Nome do programa a ser executado para realizar a
inclusão de registro da tabela pai

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btAdd IN FRAME fPage0 OR
CHOOSE OF MENU-ITEM miAdd IN MENU mbMain DO:
RUN addRecord IN THIS-PROCEDURE
(INPUT "C:/Programs/MaintenanceNoNavigationCustomer.w":U).
END.

 Trigger de Choose para o botão btCopy:


Parâmetro Descrição
ProgramName Nome do programa a ser executado para realizar a
cópia de registro da tabela pai

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btCopy IN FRAME fPage0 OR
CHOOSE OF MENU-ITEM miCopy IN MENU mbMain DO:
RUN copyRecord IN THIS-PROCEDURE
(INPUT "C:/Programs/MaintenanceNoNavigationCustomer.w":U).
END.

 Trigger de Choose para o botão btUpdate:


Parâmetro Descrição
ProgramName Nome do programa a ser executado para realizar a
alteração de registro da tabela pai

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btUpdate IN FRAME fPage0 OR
34

CHOOSE OF MENU-ITEM miUpdate IN MENU mbMain DO:


RUN updateRecord IN THIS-PROCEDURE
(INPUT "C:/Programs/MaintenanceNoNavigationCustomer.w":U).
END.

 Trigger de Choose para o botão btAddSon<PageNumber>:


Parâmetro Descrição
ProgramSon Nome do programa a ser executado para realizar a
inclusão de registro da tabela filho
PageNumber Número da página, utilizado para designar o nome de
alguns widgets, tais como btAddSon<PageNumber>,
btCopySon<PageNumber> etc

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btAddSon1 IN FRAME fPage1 DO:
{masterdetail/AddSon.i
&ProgramSon="C:/Programs/MaintenanceNoNavigationOrder.w"
&PageNumber="1"}
END.

 Trigger de Choose para o botão btCopySon<PageNumber>:


Parâmetro Descrição
ProgramSon Nome do programa a ser executado para realizar a
cópia de registro da tabela filho
PageNumber Número da página, utilizado para designar o nome de
alguns widgets, tais como btAddSon<PageNumber>,
btCopySon<PageNumber> etc

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btCopySon1 IN FRAME fPage1 DO:
{masterdetail/CopySon.i
&ProgramSon="C:/Programs/MaintenanceNoNavigationOrder.w"
&PageNumber="1"}
END.

 Trigger de Choose para o botão btUpdateSon<PageNumber>:


Parâmetro Descrição
ProgramSon Nome do programa a ser executado para realizar a
alteração de registro da tabela filho
PageNumber Número da página, utilizado para designar o nome de
alguns widgets, tais como btAddSon<PageNumber>,
btCopySon<PageNumber> etc
CAPÍTULO 3 Construindo o thinMasterDetail 35

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btUdpateSon1 IN FRAME fPage1 DO:
{masterdetail/UpdateSon.i
&ProgramSon="C:/Programs/MaintenanceNoNavigationOrder.w"
&PageNumber="1"}
END.

 Trigger de Choose para o botão btDeleteSon<PageNumber>:


Parâmetro Descrição
PageNumber Número da página, utilizado para designar o nome de
alguns widgets, tais como btAddSon<PageNumber>,
btCopySon<PageNumber> etc

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btDeleteSon1 IN FRAME fPage1 DO:
{masterdetail/DeleteSon.i
&PageNumber="1"}
END.

 Trigger de Choose para o botão btDetailSon<PageNumber>:


Parâmetro Descrição
ProgramSon Nome do programa a ser executado para realizar a
vizualização dos detalhes do registro da tabela filho
PageNumber Número da página, utilizado para designar o nome de
alguns widgets, tais como btAddSon<PageNumber>,
btCopySon<PageNumber> etc

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btDetailSon1 IN FRAME fPage1 DO:
{masterdetail/DetailSon.i
&ProgramSon="C:/Programs/MaintenanceNoNavigationOrder.w"
&PageNumber="1"}
END.

 Trigger de Choose para o botão btSearch :


Parâmetro Descrição
ProgramZoom Nome do programa a ser executado para realizar a
pesquisa de registros
36

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btSearch IN FRAME fPage0 /* Search */
OR CHOOSE OF MENU-ITEM miSearch IN MENU mbMain DO:
{method/ZoomReposition.i &ProgramZoom="C:/Programs/Zoom.w "}
END.

Método O método goToRecord é responsável pela função de Vá Para da tabela pai,


goToRecord disparada pelo botão btGoTo e pelo menu miGoTo.
O código do método está predefinido, mas necessita de pequenas alterações.
Tais como a definição dos campos a serem utilizados, tamanho da frame etc.
A seguir existe uma tabela que possui o nome dos parâmetros e suas
descrições:
Parâmetro Descrição
<c|d|i> Indica o tipo de variável (c = character, d = decimal, i =
integer)
<campo N> nomes dos campos a serem inclusos na frame de Vá
Para
<Tabela> nome da tabela a ser utilizado para definir o título da
frame de Vá Para

Exemplo de código com o preenchimento dos parâmetros:


PROCEDURE goToRecord:
/*---------------------------------------------------------------------
Purpose: Exibe dialog de Vá Para
Parameters:
Notes:
---------------------------------------------------------------------*/

DEFINE BUTTON btGoToCancel AUTO-END-KEY


LABEL "&Cancelar"
SIZE 10 BY 1
BGCOLOR 8.

DEFINE BUTTON btGoToOK AUTO-GO


LABEL "&OK"
SIZE 10 BY 1
BGCOLOR 8.

DEFINE RECTANGLE rtGoToButton


EDGE-PIXELS 2 GRAPHIC-EDGE
SIZE 35 BY 1.42
BGCOLOR 7.

DEFINE VARIABLE rGoTo AS ROWID NO-UNDO.


CAPÍTULO 3 Construindo o thinMasterDetail 37

DEFINE VARIABLE iCust-Num LIKE ttCustomer.Cust-Num NO-UNDO.

DEFINE FRAME fGoToRecord


iCust-Num AT ROW 1.21 COL 15 COLON-ALIGNED
btGoToOK AT ROW 2.63 COL 2.14
btGoToCancel AT ROW 2.63 COL 13
rtGoToButton AT ROW 2.38 COL 1
SPACE(0.28)
WITH VIEW-AS DIALOG-BOX KEEP-TAB-ORDER SIDE-LABELS NO-UNDERLINE
THREE-D SCROLLABLE FONT 1 TITLE "Vá Para Customer"
DEFAULT-BUTTON btGoToOK CANCEL-BUTTON btGoToCancel.

RUN utp/ut-trfrrp.p (input Frame fGoToRecord:Handle).


{utp/ut-liter.i "Vá_Para_<tabela>"}
ASSIGN FRAME fGoToRecord:TITLE = RETURN-VALUE.

ON "CHOOSE":U OF btGoToOK IN FRAME fGoToRecord DO:


ASSIGN iCustNum.

RUN goToKey IN {&hDBOTable} (INPUT iCustNum).


IF RETURN-VALUE = "NOK":U THEN DO:
RUN utp/ut-msgs.p (INPUT "SHOW":U, INPUT 2, INPUT "Customer").

RETURN NO-APPLY.
END.

/* Retorna rowid do registro corrente do DBO */


RUN getRowid IN {&hDBOTable} (OUTPUT rGoTo).

/* Reposiciona registro com base em um rowid */


RUN repositionRecord IN THIS-PROCEDURE (INPUT rGoTo).

APPLY "GO":U TO FRAME fGoToRecord.


END.

ENABLE iCust-Num btGoToOK btGoToCancel


WITH FRAME fGoToRecord.

WAIT-FOR "GO":U OF FRAME fGoToRecord.


END PROCEDURE.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
métodos disponíveis nesta versão. Além disso, o desenvolvedor deve usar o
preprocessador DBOVersion a fim de permitir fácil migração do programa
para o DBO 2.0.
A seguir modelo do método goToRecord, preparado para migração:
PROCEDURE goToRecord:
/*---------------------------------------------------------------------
Purpose: Exibe dialog de Vá Para
38

Parameters:
Notes:
---------------------------------------------------------------------*/

DEFINE BUTTON btGoToCancel AUTO-END-KEY


LABEL "&Cancelar"
SIZE 10 BY 1
BGCOLOR 8.

DEFINE BUTTON btGoToOK AUTO-GO


LABEL "&OK"
SIZE 10 BY 1
BGCOLOR 8.

DEFINE RECTANGLE rtGoToButton


EDGE-PIXELS 2 GRAPHIC-EDGE
SIZE 35 BY 1.42
BGCOLOR 7.

DEFINE VARIABLE cStatus AS CHARACTER NO-UNDO.

DEFINE VARIABLE rGoTo AS ROWID NO-UNDO.

DEFINE VARIABLE iCust-Num LIKE ttCustomer.Cust-Num NO-UNDO.

DEFINE FRAME fGoToRecord


iCust-Num AT ROW 1.21 COL 15 COLON-ALIGNED
btGoToOK AT ROW 2.63 COL 2.14
btGoToCancel AT ROW 2.63 COL 13
rtGoToButton AT ROW 2.38 COL 1
SPACE(0.28)
WITH VIEW-AS DIALOG-BOX KEEP-TAB-ORDER SIDE-LABELS NO-UNDERLINE
THREE-D SCROLLABLE FONT 1 TITLE "Vá Para Customer"
DEFAULT-BUTTON btGoToOK CANCEL-BUTTON btGoToCancel.

RUN utp/ut-trfrrp.p (input Frame fGoToRecord:Handle).


{utp/ut-liter.i "Vá_Para_<tabela>"}
ASSIGN FRAME fGoToRecord:TITLE = RETURN-VALUE.

ON "CHOOSE":U OF btGoToOK IN FRAME fGoToRecord DO:


ASSIGN iCustNum.

&IF DEFINED(DBOVersion) <> 0 &THEN


RUN findCust-Num IN {&hDBOTable} (INPUT iCustNum,
OUTPUT cStatus).
IF cStatus <> "":U THEN DO:
RUN utp/ut-msgs.p (INPUT "SHOW":U,
INPUT 2,
INPUT "Customer").

RETURN NO-APPLY.
END.
&ELSE
RUN goToKey IN {&hDBOTable} (INPUT iCustNum).
IF RETURN-VALUE = "NOK":U THEN DO:
RUN utp/ut-msgs.p (INPUT "SHOW":U,
CAPÍTULO 3 Construindo o thinMasterDetail 39

INPUT 2,
INPUT "Customer":U).

RETURN NO-APPLY.
END.
&ENDIF

/* Retorna rowid do registro corrente do DBO */


RUN getRowid IN {&hDBOTable} (OUTPUT rGoTo).

/* Reposiciona registro com base em um rowid */


RUN repositionRecord IN THIS-PROCEDURE (INPUT rGoTo).

APPLY "GO":U TO FRAME fGoToRecord.


END.

ENABLE iCust-Num btGoToOK btGoToCancel


WITH FRAME fGoToRecord.

WAIT-FOR "GO":U OF FRAME fGoToRecord.


END PROCEDURE.

Considerações
Quando é construído um programa utilizando o template thinMasterDetail
necessita-se realizar a implementação de lógicas auxiliares, tais como:
 programa de pesquisa de chave estrangeira;
 referência para campos de chave estrangeira.
Para tanto, deve-se utilizar o capítulo de Técnicas.

Além disso, necessita-se realizar a construção separadamente, em muitas


situações, dos programas a seguir:
 programa de pesquisa de pai;
 programa de manutenção do pai;
 programa de manutenção de filho.
Para a construção destes programas devem ser utilizados capítulos separados,
tais como:
 Construindo o thinZoom;
 Construindo o thinMaintenanceNoNavigation.
41

CAPÍTULO 4

Construindo o thinMaintenanceNoNavigation

Neste estão informações para que o desenvolvedor possa construir um


programa baseado no template thinMaintenanceNoNavigation.
A seguir está um exemplo de um programa construído com o template
thinMaintenanceNoNavigation:

Vale ressaltar que toda a exemplificação será feita utilizando o banco de dados
Sports.
42

Características As características deste são:


 realiza a manutenção de um único registro, seja este passado como
parâmetro ou não;
 realiza a manutenção de registro de tabelas filho, associada a tabela pai;
 o gerenciamento das páginas do folder é feito pelo programa
objects/thinFolder.w;

 faz uso do sistema de tradução de .R, bastando para tanto identificar as


strings que não devem ser traduzidas com :U (Exemplo: "CHOOSE":U).
Observação: O identificador :T no início de alguns comentários, é usado para a
tradução dos fontes dos templates para outros idiomas. Este identificador não
afeta em nada a funcionalidade do programa.

Tarefas
A seguir é apresentada a lista de tarefas para desenvolvimento do programa.

Preprocessors Inicialmente devem ser definidos os valores dos preprocessors padrão do


programa.
Quando o programa for utilizado para manutenir uma tabela pai ou tabela
indepentende, deve-se utilizar os preprocessors padrão descritos na tabela a
seguir:
Preprocessor Descrição
Program Nome do programa – Formato (XX9999)
Version Versão do programa – Formato (9.99.99.999)
Folder O valor YES indica que o programa terá folder
InitialPage Indica em qual página o programa irá iniciar
FolderLabels Descrição de cada uma das páginas do folder
ttTable Nome da temp-table utilizada para comunicação com o
DBO
hDBOTable Nome da variável que contém o handle do DBO
DBOTable Nome da tabela principal do DBO
page0KeyFields Nome dos campos chaves que estão na frame fPage0
pageNFields Nome dos campos que estão nas frames fPageN, N
CAPÍTULO 4 Construindo o thinMaintenanceNoNavigation 43

Preprocessor Descrição
indica o número da página, podendo variar de 0 até 8

Observação O preprocessor Program refere-se ao nome com o qual o programa


está ou será cadastrado no menu.
Exemplo de código com o preenchimento dos preprocessadors:
&GLOBAL-DEFINE Program thinMaintenanceNoNavigation
&GLOBAL-DEFINE Version 1.00.00.000

&GLOBAL-DEFINE Folder YES


&GLOBAL-DEFINE InitialPage 1

&GLOBAL-DEFINE FolderLabels Others

&GLOBAL-DEFINE ttTable ttCustomer


&GLOBAL-DEFINE hDBOTable hDBOCustomer
&GLOBAL-DEFINE DBOTable Customer

&GLOBAL-DEFINE page0KeyFields ttCustomer.Cust-Num


&GLOBAL-DEFINE page0Fields ttCustomer.Name
&GLOBAL-DEFINE page1Fields ttCustomer.Address ~
ttCustomer.Address2 ~
ttCustomer.City ~
ttCustomer.State ~
ttCustomer.Country

Quando o desenvolvedor optar por retirar uma ou mais funções do programa,


deve-se alterar o conteúdo do preprocessor correspondente.
Para retirar o botão “Salvar”, o desenvolvedor deve incluir o preprocessor
padrão ExcludeBtSave.
&GLOBAL-DEFINE ExcludeBtSave YES

Mas caso o programa seja utilizado para manutenir uma tabela filho, deve-se
utilizar os preprocessors padrão descritos na tabela a seguir:
Preprocessor Descrição
Program Nome do programa – Formato (XX9999)
Version Versão do programa – Formato (9.99.99.999)
Folder O valor YES indica que o programa terá folder
InitialPage Indica em qual página o programa irá iniciar
FolderLabels Descrição de cada uma das páginas do folder
ttTable Nome da temp-table filho (principal) utilizada para
comunicação com o DBO filho (principal)
44

Preprocessor Descrição
hDBOTable Nome da variável que contém o handle do DBO filho
(principal)
DBOTable Nome da tabela principal do DBO filho (principal)
ttParent Nome da temp-table pai (secundária) utilizada para
comunicação com o DBO pai (secundário)
DBOParent Nome da tabela principal do DBO pai (secundário)
page0KeyFields Nome dos campos chaves da temp-table filho (principal)
que estão na frame fPage0
page0ParentFields Nome dos campos da temp-table pai (secundária) que
estão na frame fPage0
pageNFields Nome dos campos da temp-table filho (principal) que
estão nas frames fPageN, N indica o número da página,
podendo variar de 0 até 8

Observação O preprocessor Program refere-se ao nome com o qual o programa


está ou será cadastrado no menu.
Exemplo de código com o preenchimento dos preprocessadors:
&GLOBAL-DEFINE Program thinMaintenanceNoNavigation
&GLOBAL-DEFINE Version 1.00.00.000

&GLOBAL-DEFINE Folder YES


&GLOBAL-DEFINE InitialPage 1

&GLOBAL-DEFINE FolderLabels Others

&GLOBAL-DEFINE ttTable ttOrder


&GLOBAL-DEFINE hDBOTable hDBOOrder
&GLOBAL-DEFINE DBOTable Order

&GLOBAL-DEFINE ttParent ttCustomer


&GLOBAL-DEFINE DBOParent Customer

&GLOBAL-DEFINE page0KeyFields ttOrder.Order-Num


&GLOBAL-DEFINE page0ParentFields ttCustomer.Cust-Num ~
ttCustomer.Name
&GLOBAL-DEFINE page1Fields ttOrder.Order-Date ~
ttOrder.Promise-Date ~
ttOrder.Ship-Date ~
ttOrder.Sales-Rep ~
ttOrder.PO ~
ttOrder.Terms ~
ttOrder.Carrier ~
ttOrder.Instructions
CAPÍTULO 4 Construindo o thinMaintenanceNoNavigation 45

Quando o desenvolvedor optar por retirar uma ou mais funções do programa,


deve-se alterar o conteúdo do preprocessor correspondente.
Para retirar o botão “Salvar”, o desenvolvedor deve incluir o preprocessor
padrão ExcludeBtSave.
&GLOBAL-DEFINE ExcludeBtSave YES

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se criar um
preprocessador chamado DBOVersion, na sessão Definitions, com o valor
1.1. A seguir modelo de sua definição:
&GLOBAL-DEFINE DBOVersion 1.1

Temp-Table de Criar a temp-table que é utilizada para realizar a comunicação com o DBO. E
Comunicação deve estar disponível para inclusão de campos em tela.
Para tanto deve-se utilizar o menu Tools | Procedure Settings, botão:

A tela a seguir é aberta, nesta deve criar-se a temp-table e definir um campo


chamado r-Rowid. E ainda, a definição desta temp-table deve ser idêntica a
definição da temp-table do DBO.
46

Mas caso o programa seja utilizado para manutenção de tabelas filho, devem-
se criar as temp-tables tanto para as tabelas filho como para a tabela pai.
A tela a seguir exibe as definições de temp-tables para um programa de
manutenção de tabelas filho:
CAPÍTULO 4 Construindo o thinMaintenanceNoNavigation 47

Parâmetros para Como este template é utilizado para estilos diferentes de manutenção. Deve-se
executação do definir os parâmetros como o estilo utilizado.
programa Se o programa for usado para a manutenção de uma tabela pai, deve-se definir
os parâmetros a seguir para o programa:
/* Parameters Definitions --- */
DEFINE INPUT PARAMETER prTable AS ROWID NO-UNDO.
DEFINE INPUT PARAMETER pcAction AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER phCaller AS HANDLE NO-UNDO.

A tabela a seguir descreve a funcionalidade de cada um dos parâmetros


definidos:
Parâmetro Descrição
prTable Rowid da tabela a ser manutenida pelo programa, caso
seja uma inclusão ou cópiar deve-se utilizar ? como
48

Parâmetro Descrição
valor para o parâmetro
pcAction Indica a ação a ser tomada pelo programa, podendo ter
os valores: Add = Inclusão, Copy = Cópia e Update =
Alteração
phCaller Handle do programa executor

Mas se o programa for usado para a manutenção de uma tabela filho, deve-se
definir os parâmetros a seguir para o programa:
/* Parameters Definitions --- */
DEFINE INPUT PARAMETER prTable AS ROWID NO-UNDO.
DEFINE INPUT PARAMETER prParent AS ROWID NO-UNDO.
DEFINE INPUT PARAMETER pcAction AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER phCaller AS HANDLE NO-UNDO.
DEFINE INPUT PARAMETER piSonPageNumber AS INTEGER NO-UNDO.

A tabela a seguir descreve a funcionalidade de cada um dos parâmetros


definidos:
Parâmetro Descrição
prTable Rowid da tabela filho (principal) a ser manutenida pelo
programa, caso seja uma inclusão ou cópiar deve-se
utilizar ? como valor para o parâmetro
prParent Rowid da tabela pai (secundária) a ser utilizada pelo
programa
pcAction Indica a ação a ser tomada pelo programa, podendo ter
os valores: Add = Inclusão, Copy = Cópia e Update =
Alteração
phCaller Handle do programa executor
piSonPageNumber Número da página associado a tabela filho, no programa
executor, utilizado posicionar o browse filho no registro
atualizado ou criado

Método O método saveParentFields é responsável pela atualização dos campos


saveParentFields referentes a tabela pai que estão na tabela filho.
A seguir está exemplo de código do método:
/*-----------------------------------------------------------------
Purpose: Salva valores dos campos da tabela filho ({&ttTable})
com base nos campos da tabela pai ({&ttParent})
Parameters:
Notes: Este método somente é executado quando a variável
pcAction possuir os valores ADD ou COPY
-----------------------------------------------------------------*/
CAPÍTULO 4 Construindo o thinMaintenanceNoNavigation 49

/*--- Atualiza campo ttOrder.Cust-Num com o valor do


ttCustomer.Cust-Num ---*/
ASSIGN ttOrder.Cust-Num = ttCustomer.Cust-Num.

RETURN "OK":U.
END PROCEDURE.

Como o template possui estilos diferentes, este método somente deve ser
mantido no caso do programa ser utilizado para a manutenção de registro de
tabela filho.

Páginas do folder O template, inicialmente, possui a definição de 2 (duas) páginas. Mas o


desenvolvedor pode retirá-las, a fim de manter somente a página principal, ou
acrescentar novas páginas, até o limite máximo de 8 (oito) páginas.
No entanto, se o programa não possuir as páginas fPage0 e fPage1, não é
possível inicializar o folder em tempo de execução (EPC). Por isso, aconselha-
se que, mesmo não sendo necessário o folder no momento do desenvolvimento
do programa, o programador conserve as páginas fPage0 e fPage1, alterando
apenas o pré-procesador Folder NO.
A frame principal (fPage0) somente pode ter sua altura alterada, o restante
das propriedades deve ser mantido. A altura deste é definida da forma a seguir:
 posicionamento da linha acrescido da altura dos frames das páginas e,
ainda, mais 1.45.
O posicionamento da barra de ferramentas e dos botões deve ser definido da
forma a seguir:
 A linha na qual deve estar o widget rtToolBar fica a 0.63 antes do final da
fPage0.
 Os botões devem estar na linha do rtToolBar acrecido de 0.23.
Para cada página está relacionado um widget frame, possuindo a nomenclatura
fPage<PageNumber>. Para estes frames deve ser definida o fonte 1 e
seguido as regra de posicionamento e tamanho, descrita a seguir:
 devem estar posicionados na coluna 3.50;
 a linha na qual devem estar posicionados fica a 1.45 abaixo do último
widget da frame principal (fPage0);
 a largura não deve ser alterada (84.43);
50

 a altura é definida através da quantidade de widgets em linha acrescido de


0.25.
A imagem a seguir exibe como fica a janela do programa durante sua
construção:

Vale ressaltar que os labels das páginas não aparecem em tempo de


desenvolvimento, pois são criados durante a execução do programa. Por isso
faz-se necessário o espaço entre os frames das páginas e o último widget da
frame principal (fPage0).
Observação Para os campos do tipo fill-in’s, deve ser observado se o mesmo possue trigger
de "LEAVE"/"VALUE-CHANGED" e não tenha lupa como cursor do mouse ou um botão de
zoom na sua direita; ou possua trigger de "ENTRY". Caso o fill-in se encaixe em uma das
opções acima, deve ser efetuado o registro para o WebEnabler, conforme técnica Como registrar
campo do tipo Fill-in para o WebEnabler do Manual de Padrões.
O WebEnabler já registra automaticamente o evento de "LEAVE" para TODOS os fill-ins que
possuírem a lupa como cursor do mouse, ou que possuírem um botão de zoom na sua direita.
Portanto não é necessário efetuar o registro para esses fill-ins.

Disposição dos Quando for necessário fazer a inclusão de widgets (sejam campos ou widgets
widgets nas comuns) deve-se primeiramente selecionar o frame de trabalho. Para tanto usa-
páginas se o botão:
CAPÍTULO 4 Construindo o thinMaintenanceNoNavigation 51

A tela a seguir é aberta, nesta deve selecionar-se a frame desejada e clicar-se


no botão que está indicado:

Após a seleção do frame de trabalho, deve-se fazer a inclusão dos widgets.


Para os widgets da temp-table de comunicação deve-se utilizar o botão a
seguir:

A tela a seguir é aberta, nesta deve selecionar-se o item Temp-Tables, a temp-


table desejada e logo após os campos a serem inclusos na frame de trabalho:
52

Após a inclusão dos campos, ou widgets comuns, devem ser feitas algumas
alterações de suas propriedades. Estas são descritas a seguir:
 devem estar dispostos em linha, e caso necessário em colunas;
 para widgets do tipo fill-in, sua altura deve ser de 0.88;
 para widgets dos tipos combo-box, suas alturas devem ser de 1.00;
 para widgets dos tipos editores ou list-box ou radio-set, suas alturas devem
ser definidas pelo próprio desenvolvedor;
 para os widgets que fazem parte do índice único e suas descrições, devem
ser dispostos no retângulo rtKeys;
 a linha na qual os widgets que estão na primeira linha do retângulo rtKeys,
deve ser 1.17; os demais devem estar a distância de 1.00 do widget
anterior;
 a linha na qual os widgets que estão na primeira linha dos frames das
páginas, deve ser 1.17; os demais devem estar a distância de 1.00 do
widget anterior.

Considerações
Quando é construído um programa utilizando o template
thinMaintenanceNoNavigation necessita-se realizar a implementação de
lógicas auxiliares, tais como:
 programa de pesquisa de chave estrangeira;
CAPÍTULO 4 Construindo o thinMaintenanceNoNavigation 53

 referência para campos de chave estrangeira.


Para tanto, deve-se utilizar o capítulo de Técnicas.
55

CAPÍTULO 5

Construindo o thinZoom

Introdução Neste estão informações para que o desenvolvedor possa construir um


programa baseado no template thinZoom.
A seguir está um exemplo de um programa construído com o template
thinZoom:

Vale ressaltar que toda a exemplificação será feita utilizando o banco de dados
Sports.
56

Características As características deste são:


 possui função para implementação de novos registros;
 pode ser utilizado para pesquisa de chaves estrangeiras ou para
reposicionamento;
 cada uma das páginas é utiliza para identificar as diferentes classificações
da tabela do programa;
 o gerenciamento das páginas do folder é feito pelo programa
objects/thinFolder.w;

 faz uso do sistema de tradução de .R, bastando para tanto identificar as


strings que não devem ser traduzidas com :U (Exemplo: "CHOOSE":U).
Observação: O identificador :T no início de alguns comentários, é usado para a
tradução dos fontes dos templates para outros idiomas. Este identificador não
afeta em nada a funcionalidade do programa.

Tarefas
A seguir é apresentada a lista de tarefas para desenvolvimento do programa.

Preprocessors Inicialmente devem ser definidos os valores dos preprocessors padrões do


programa.
A seguir é apresentada tabela com o nome dos preprocessors padrões e suas
descrições:
Preprocessor Descrição
Program Nome do programa – Formato (XX9999)
Version Versão do programa – Formato (9.99.99.999)
InitialPage Indica em qual página o programa irá iniciar
FolderLabels Descrição de cada uma das páginas do folder
Range O valor YES indica que o programa usará criação
automática de faixa
FieldsRangePageN Nome dos campos que são utilizados para a criação
automática de faixas da página N, separados por vírgula
CAPÍTULO 5 Construindo o thinZoom 57

Preprocessor Descrição
e sem limitação de número de campos. N indica o
número da página, podendo variar de 1 até 8. Neste pré-
processador é necessário informar o nome da base de
dados + nome da tabela + nome do campo. Ex:
sports.customer.cust-num
FieldsAnyKeyPageN Os valores YES e NO, separados por “,”, indicarão quais
campos conterão o evento de ANYKEY. N indica o
número da página, podendo variar de 1 até 8
TtTableN Nome da temp-table N utilizada para comunicação com
o DBO N, N indica o número da página, podendo variar
de 1 até 8
HDBOTableN Nome da variável que contém o handle do DBO N, N
indica o número da página, podendo variar de 1 até 8
DBOTableN Nome da tabela principal do DBO N, N indica o número
da página, podendo variar de 1 até 8
PageNBrowse Nome do browser N que está na frame fPageN, N indica
o número da página, podendo variar de 1 até 8

Observação O preprocessor Program refere-se ao nome com o qual o programa


está ou será cadastrado no menu.
Exemplo de código com o preenchimento dos preprocessadores:
&GLOBAL-DEFINE Program thinZoom
&GLOBAL-DEFINE Version 1.00.00.000

&GLOBAL-DEFINE InitialPage 1
&GLOBAL-DEFINE FolderLabels Cust-Num,Name

&GLOBAL-DEFINE Range YES

&GLOBAL-DEFINE FieldsRangePage1 sports.Customer.Cust-Num


&GLOBAL-DEFINE FieldsRangePage2 sports.Customer.Name
&GLOBAL-DEFINE FieldsRangePage3
&GLOBAL-DEFINE FieldsRangePage4
&GLOBAL-DEFINE FieldsRangePage5
&GLOBAL-DEFINE FieldsRangePage6
&GLOBAL-DEFINE FieldsRangePage7
&GLOBAL-DEFINE FieldsRangePage8
&GLOBAL-DEFINE FieldsAnyKeyPage1 YES
&GLOBAL-DEFINE FieldsAnyKeyPage2 NO
&GLOBAL-DEFINE FieldsAnyKeyPage3
&GLOBAL-DEFINE FieldsAnyKeyPage4
&GLOBAL-DEFINE FieldsAnyKeyPage5
&GLOBAL-DEFINE FieldsAnyKeyPage6
58

&GLOBAL-DEFINE FieldsAnyKeyPage7
&GLOBAL-DEFINE FieldsAnyKeyPage8

&GLOBAL-DEFINE ttTable1 ttCustomer


&GLOBAL-DEFINE hDBOTable1 hDBOCustomer
&GLOBAL-DEFINE DBOTable1 Customer

&GLOBAL-DEFINE ttTable2 ttCustomer2


&GLOBAL-DEFINE hDBOTable2 hDBOCustomer2
&GLOBAL-DEFINE DBOTable2 Customer

&GLOBAL-DEFINE page1Browse brTable1


&GLOBAL-DEFINE page2Browse brTable2

Quando o desenvolvedor optar por retirar uma ou mais funções do programa,


deve-se alterar o conteúdo do preprocessor correspondente.
Para definir o número de registros que devem ser retornados para o browse,
deve-se utilizar os preprocessors padrão descritos anteriormente e acrescentar
o preprocessor padrão a seguir:
Preprocessor Descrição
NumRowsReturned Número de registros que devem ser retornados no
browse

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se criar um
preprocessador chamado DBOVersion, na sessão Definitions, com o valor
1.1. A seguir modelo de sua definição:
&GLOBAL-DEFINE DBOVersion 1.1

Temp-Table de Criar as temp-tables que são utilizadas para realizar a comunicação com os
Comunicação DBOs. E devem estar disponíveis para a criação dos browsers.
Para tanto deve-se utilizar o menu Tools | Procedure Settings, botão:

A tela a seguir é aberta, nesta devem criar-se as temp-tables e definir um


campo chamado r-Rowid. E ainda, as definições destas temp-tables devem
ser idênticas as definições das temp-tables dos DBOs.
CAPÍTULO 5 Construindo o thinZoom 59

Queries para os A query do browser deve ser gerada com um FOR EACH simples na TEMP-
browses TABLE de comunicação da interface. Em cada página do Zoom.
60

Faixas de Entrada As faixas para entrada de valores com as quais o usuário final define os
registros a serem exibidos nos browsers devem ser compatíveis com as
restrições existentes no programa DBO.
A construção das faixas pode ser feita de forma automática, basta o
preenchimento dos pré-processadores Range, FieldsRangePageN e
FieldsAnyKeyPageN que estão explicados na tabela do tópico Preprocessors.
Caso o desenvolvedor opte por criar as faixas manualmente, deve utilizar as
regras a seguir:
 incluir widgets compatíveis com as restrições existentes nos DBOs;
 caso utilize-se fill-ins, devem possuir a altura 0.88, somente o primeiro
deve possuir label e devem utilizar as imagens: image/im-fir.bmp e
image/im-las.bmp para indicar a faixa inicial e final caso necessário;
CAPÍTULO 5 Construindo o thinZoom 61

 caso utilize-se combo-boxs, devem possuir a altura 0.88, somente o


primeiro deve possuir label e devem utilizar as imagens: image/im-
fir.bmp e image/im-las.bmp para indicar a faixa inicial e final caso
necessário;
 incluir um botão chamado btCheck<PageNumber>, altura 1.00, largura
5.00, imagem image/im-chck1.bmp e que execute o método
setConstraints passando como parâmetro o número da página
correspondente ao botão.
A seguir está a imagem do botão o código código exemplo de sua trigger:

ON CHOOSE OF btCheck1 DO:


RUN setConstraints IN THIS-PROCEDURE (INPUT 1).
END.

Instâncias do As criações das instâncias do DBOs devem ser feitas manualmente, utilizando
DBOs ou não o recurso de RPC. Logo após deve-se definir as restrições iniciais caso
necessário.
As instâncias dos DBOs são feitas na seção Main Block do programa.
A seguir existe uma tabela que possui o nome dos parâmetros e suas
descrições:

Parâmetro Descrição
DBOProgram Nome físico do programa DBO
Description Identifica o nome da constraint a ser utilizada
inicialmente para o DBO

Exemplo de código com o preenchimento dos parâmetros:


PROCEDURE initializeDBOs:
/*-----------------------------------------------------------------
Purpose: Inicializa DBOs
Parameters:
Notes:
-----------------------------------------------------------------*/

/*--- Verifica se o DBO já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOTable1}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOCustomer.p YES}
62

{btb/btb008za.i2 C:/Programs/DBOCustomer.p '' {&hDBOTable1}}


END.

/*--- Abre query CustNum do DBO ---*/


RUN openQueryStatic IN {&hDBOTable1} (INPUT "CustNum":U) NO-ERROR.

/*--- Verifica se o DBO já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOTable2}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOCustomer.p YES}
{btb/btb008za.i2 C:/Programs/DBOCustomer.p '' {&hDBOTable2}}
END.

/*--- Abre query CustNum do DBO ---*/


RUN openQueryStatic IN {&hDBOTable2} (INPUT "Name":U) NO-ERROR.

RETURN "OK":U.
END PROCEDURE.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
métodos disponíveis nesta versão. Além disso, o desenvolvedor deve usar o
preprocessador DBOVersion a fim de permitir fácil migração do programa
para o DBO 2.0.
A seguir modelo de instância de BO 1.1, preparado para migração:
PROCEDURE initializeDBOs:
/*-----------------------------------------------------------------
Purpose: Inicializa DBOs
Parameters:
Notes:
-----------------------------------------------------------------*/

/*--- Verifica se o DBO já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOTable1}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOCustomer.p YES}
{btb/btb008za.i2 C:/Programs/DBOCustomer.p '' {&hDBOTable1}}
END.

/*--- Abre query CustNum do DBO ---*/


&IF DEFINED(DBOVersion) <> 0 &THEN
RUN openQuery IN {&hDBOTable1} (INPUT 1) NO-ERROR.
&ELSE
RUN openQueryStatic IN {&hDBOTable1} (INPUT "CustNum":U) NO-
ERROR.
&ENDIF

/*--- Verifica se o DBO já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOTable2}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOCustomer.p YES}
{btb/btb008za.i2 C:/Programs/DBOCustomer.p '' {&hDBOTable2}}
END.
CAPÍTULO 5 Construindo o thinZoom 63

/*--- Abre query CustNum do DBO ---*/


&IF DEFINED(DBOVersion) <> 0 &THEN
RUN openQuery IN {&hDBOTable2} (INPUT 2) NO-ERROR.
&ELSE
RUN openQueryStatic IN {&hDBOTable2} (INPUT "Name":U) NO-ERROR.
&ENDIF

RETURN "OK":U.
END PROCEDURE.

Páginas do folder O template, inicialmente, possui a definição de 2 (duas) páginas. Mas o


desenvolvedor pode manter somente uma, ou acrescentar novas páginas, até o
limite máximo de 8 (oito) páginas.
A frame principal (fPage0) somente pode ter sua altura alterada, o restante
das propriedades deve ser mantido. A altura deste é definida da forma a seguir:
 posicionamento da linha acrescido da altura dos frames das páginas e,
ainda, mais 1.45.
Para cada página está relacionado um widget frame, possuindo a nomenclatura
fPage<PageNumber>. Para estes frames deve ser definida o fonte 1 e
seguido as regra de posicionamento e tamanho, descrita a seguir:
 devem estar posicionados na coluna 3.50;
 devem estar posicionados na linha 2.45;
 a largura não deve ser alterada (84.43);
 a altura, preferencialmente, deve ser mantida (10.63);
A imagem a seguir exibe como fica a janela do programa durante sua
construção:
64

Vale ressaltar que os labels das páginas não aparecem em tempo de


desenvolvimento, pois são criados durante a execução do programa. Por isso
faz-se necessário o espaço entre os frames das páginas e o último widget da
frame principal (fPage0).
Observação Para os campos do tipo fill-in’s, deve ser observado se o mesmo possue trigger
de "LEAVE"/"VALUE-CHANGED" e não tenha lupa como cursor do mouse ou um botão de
zoom na sua direita; ou possua trigger de "ENTRY". Caso o fill-in se encaixe em uma das
opções acima, deve ser efetuado o registro para o WebEnabler, conforme técnica Como registrar
campo do tipo Fill-in para o WebEnabler do Manual de Padrões.
O WebEnabler já registra automaticamente o evento de "LEAVE" para TODOS os fill-ins que
possuírem a lupa como cursor do mouse, ou que possuírem um botão de zoom na sua direita.
Portanto não é necessário efetuar o registro para esses fill-ins.

Disposição dos Quando for necessário fazer a inclusão de widgets (sejam campos, widgets
widgets nas comuns ou browses) deve-se primeiramente selecionar o frame de trabalho.
páginas Para tanto usa-se o botão:

A tela a seguir é aberta, nesta deve selecionar-se a frame desejada e clicar-se


no botão que está indicado:
CAPÍTULO 5 Construindo o thinZoom 65

Após a seleção do frame de trabalho, deve-se fazer a inclusão dos widgets.


Para os widgets browsers, devem set feitas algumas alterações de suas
propriedades. Estas são descritas a seguir:
 a fonte deve ser 2;
 a largura deve ser 82.00;
 a altura deve ser 8.00;
 não deve-se utilizar a opção INDEXED-REPOSITION;
 Na definição do browse, a opção Fields Returned deve conter o valor All
Fields.

Método O método openQueries é responsável por realizar a abertura dos browsers


openQueries com os dados dos DBOs. Para tanto é feito o uso do include
zoom/OpenQueries.i para atualizar os dados dos browsers.
66

Na criação das queries dos browsers, deve-se levar em consideração as


aberturas de query que serão utilizadas nos DBOs, sendo assim, devem ser
iguais.
Uma das características deste include é a de trazer somente os 40 (quarenta)
primeiros registros associados aos browsers. Os próximos registros são
trazidos quando ocorrem os eventos de Cursor-Down, End, Off-End e
Page-Down, utilizando o mesmo método.
A seguir existe uma tabela que possui o nome dos parâmetros e suas
descrições:
Parâmetro Descrição
Query Identifica o nome da query a ser utilizada para realizar
a abertura dos DBOs
PageNumber Número da página, utilizado para designar o nome de
alguns widgets, tais como btImplant etc

Exemplo de código com o preenchimento dos parâmetros:


PROCEDURE openQueries:
/*------------------------------------------------------------------
Purpose: Atualiza browsers
Parameters:
Notes:
------------------------------------------------------------------*/

{zoom/OpenQueries.i &Query="CustNum"
&PageNumber="1"}

{zoom/OpenQueries.i &Query="Name"
&PageNumber="2"}

RETURN "OK":U.
END PROCEDURE.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
novos parâmetros para o include zoom/OpenQueries.i. A seguir existe uma
tabela que possui o nome dos novos parâmetros e suas descrições:
Parâmetro Descrição
QueryNumber número que identifica a query, a ser utilizado para
passagem de parâmetro para o método openQuery
CAPÍTULO 5 Construindo o thinZoom 67

Exemplo de código com o preenchimento dos novos parâmetros:


PROCEDURE openQueries:
/*------------------------------------------------------------------
Purpose: Atualiza browsers
Parameters:
Notes:
------------------------------------------------------------------*/

{zoom/OpenQueries.i &Query="CustNum"
&PageNumber="1"
&QueryNumber="1"}

{zoom/OpenQueries.i &Query="Name"
&PageNumber="2"
&QueryNumber="2"}

RETURN "OK":U.
END PROCEDURE.

Método O método setConstraints é responsável por realizar a abertura dos


setConstraints browsers, com as restrições indicadas pelo usuário final, com os dados dos
DBOs. Para tanto é feito o uso dos métodos
setConstraint<Description> existentes no DBOs.
O parâmetro recebido pelo método indica o número da página que deve ser
utilizada para verificar qual o grupo de restrições a serem utilizadas.
Exemplo de código:
PROCEDURE setConstraints:
/*-----------------------------------------------------------------
Purpose: Seta constraints e atualiza o browse, conforme
número da página passado como parâmetro
Parameters: recebe número da página
Notes:
-----------------------------------------------------------------*/

DEFINE INPUT PARAMETER pPageNumber AS INTEGER NO-UNDO.

/*--- Seta constraints conforme número da página ---*/


CASE pPageNumber:
WHEN 1 THEN
/*--- Seta Constraints para o DBOTable1 ---*/
RUN setConstraintCustNum IN {&hDBOTable1}
(INPUT fnIniRangeIntPage(INPUT 1, INPUT 1),
INPUT fnEndRangeIntPage(INPUT 1, INPUT 1)).

WHEN 2 THEN
/*--- Seta Constraints para o DBOTable2 ---*/
RUN setConstraintName IN {&hDBOTable2}
(INPUT fnIniRangeCharPage(INPUT 2, INPUT 1),
68

INPUT fnEndRangeCharPage(INPUT 2, INPUT 1)).


END CASE.

/*--- Seta variável iConstraintPageNumber com o número da


página atual
Esta variável é utilizada no método openQueries ---*/
ASSIGN iConstraintPageNumber = pPageNumber.

/*--- Atualiza browse ---*/


RUN openQueries IN THIS-PROCEDURE.

RETURN "OK":U.
END PROCEDURE.

Quando é feito uso de faixas automáticas deve-se utilizar as funções a seguir


para retornar os valores informados pelo usuário final.
Função Descrição
FnIniRangeCharPage Retorna valor de tela, do campo da faixa inicial, no
formato caracter, recebe como parâmetro o número
da página e o número da posição do campo na faixa
automática.
FnEndRangeCharPage Retorna valor de tela, do campo da faixa final, no
formato caracter, recebe como parâmetro o número
da página e o número da posição do campo na faixa
automática.
FnIniRangeIntPage Retorna valor de tela, do campo da faixa inicial, no
formato inteiro, recebe como parâmetro o número da
página e o número da posição do campo na faixa
automática.
FnEndRangeIntPage Retorna valor de tela, do campo da faixa final, no
formato inteiro, recebe como parâmetro o número da
página e o número da posição do campo na faixa
automática.
FnIniRangeDatePage Retorna valor de tela, do campo da faixa inicial, no
formato data, recebe como parâmetro o número da
página e o número da posição do campo na faixa
automática.
FnEndRangeDatePage Retorna valor de tela, do campo da faixa final, no
formato data, recebe como parâmetro o número da
página e o número da posição do campo na faixa
automática.
FnIniRangeDecPage Retorna valor de tela, do campo da faixa inicial, no
formato decimal, recebe como parâmetro o número
da página e o número da posição do campo na faixa
automática.
FnEndRangeDecPage Retorna valor de tela, do campo da faixa final, no
CAPÍTULO 5 Construindo o thinZoom 69

Função Descrição
formato decimal, recebe como parâmetro o número
da página e o número da posição do campo na faixa
automática.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
métodos disponíveis nesta versão. Além disso, o desenvolvedor deve usar o
preprocessador DBOVersion a fim de permitir fácil migração do programa
para o DBO 2.0.
A seguir modelo do método setConstraints, preparado para migração:
PROCEDURE setConstraints:
/*-----------------------------------------------------------------
Purpose: Seta constraints e atualiza o browse, conforme
número da página passado como parâmetro
Parameters: recebe número da página
Notes:
-----------------------------------------------------------------*/

DEFINE INPUT PARAMETER pPageNumber AS INTEGER NO-UNDO.

/*--- Seta constraints conforme número da página ---*/


CASE pPageNumber:
WHEN 1 THEN
&IF DEFINED(DBOVersion) <> 0 &THEN
/*--- Seta Constraints para o DBOTable1 ---*/
RUN setConstraint1 IN {&hDBOTable1}
(INPUT fnIniRangeIntPage(INPUT 1, INPUT 1),
INPUT fnEndRangeIntPage(INPUT 1, INPUT 1)).
&ELSE
/*--- Seta Constraints para o DBOTable1 ---*/
RUN setConstraintCustNum IN {&hDBOTable1}
(INPUT fnIniRangeIntPage(INPUT 1, INPUT 1),
INPUT fnEndRangeIntPage(INPUT 1, INPUT 1)).
&ENDIF

WHEN 2 THEN
&IF DEFINED(DBOVersion) <> 0 &THEN
/*--- Seta Constraints para o DBOTable2 ---*/
RUN setConstraint1 IN {&hDBOTable2}
(INPUT fnIniRangeCharPage(INPUT 2, INPUT 1),
INPUT fnEndRangeCharPage(INPUT 2, INPUT 1)).
&ELSE
/*--- Seta Constraints para o DBOTable2 ---*/
RUN setConstraintName IN {&hDBOTable2}
(INPUT fnIniRangeCharPage(INPUT 2, INPUT 1),
INPUT fnEndRangeCharPage(INPUT 2, INPUT 1)).
&ENDIF
70

END CASE.

/*--- Seta variável iConstraintPageNumber com o número da


página atual
Esta variável é utilizada no método openQueries ---*/
ASSIGN iConstraintPageNumber = pPageNumber.

/*--- Atualiza browse ---*/


RUN openQueries IN THIS-PROCEDURE.

RETURN "OK":U.
END PROCEDURE.

Método O método returnFieldsPage<PageNumber> é responsável por retornar os


returnFieldsPage valores dos campos do registro selecionado pelo usuário final.
<PageNumber> A seguir existe uma tabela com a descrição dos parâmetros recebidos pelo
método:
Preprocessor Descrição
pcField Indica o nome do campo que deseja-se retornar o valor
PcFieldValue Valor do campo em formato caracter

Exemplo de código:
PROCEDURE returnFieldsPage1:
/*-----------------------------------------------------------------
Purpose: Retorna valores dos campos da página 1
Parameters: recebe nome do campo
retorna valor do campo
Notes:
-----------------------------------------------------------------*/

DEFINE INPUT PARAMETER pcField AS CHARACTER NO-UNDO.


DEFINE OUTPUT PARAMETER pcFieldValue AS CHARACTER NO-UNDO.

IF AVAILABLE ttCustomer THEN DO:


CASE pcField:
WHEN "Cust-Num":U THEN
ASSIGN pcFieldValue = STRING(ttCustomer.Cust-Num).
WHEN "Name":U THEN
ASSIGN pcFieldValue = STRING(ttCustomer.Name).
WHEN "Credit-Limit":U THEN
ASSIGN pcFieldValue = STRING(ttCustomer.Credit-Limit).
WHEN "Discount":U THEN
ASSIGN pcFieldValue = STRING(ttCustomer.Discount).
WHEN "Balance":U THEN
ASSIGN pcFieldValue = STRING(ttCustomer.Balance).
END CASE.
END.
CAPÍTULO 5 Construindo o thinZoom 71

RETURN "OK":U.
END PROCEDURE.

Triggers de botões Para os botões padrão existem métodos ou includes padrão que precisam ser
padrão definidos.
Inicialmente todos os botões já estão com valores prefixados, somente
necessitanto serem alterados em alguns casos.
A seguir existe uma tabela que possui a identificação das triggers, dos
parâmetros e suas descrições:
 Trigger de Choose para o botão btImplant<PageNumber>:
Parâmetro Descrição
ProgramImplant Nome do programa de implantação a ser executado
para realizar a inclusão de novos registro
PageNumber Indica o número da página associado ao botão

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btImplant IN FRAME fPage1 DO:
{zoom/Implant.i
&ProgramImplant="C:/Programs/CustomerMaintenance.w"
&PageNumber="1"}
END.
73

CAPÍTULO 6

Construindo o thinWindow

Introdução Neste estão informações para que o desenvolvedor possa construir um


programa baseado no template thinWindow.
A seguir estão exemplos de dois programas construídos com o template
thinWindow:
74

Vale ressaltar que toda a exemplificação será feita utilizando o banco de dados
Sports.

Características As características deste são:


 pode ser utilizado tanto como Janela Mestre ou Janela Detalhe, usando
para isto uma ou mais páginas;
 o gerenciamento das páginas do folder é feito pelo programa
objects/thinFolder.w;

 faz uso do sistema de tradução de .R, bastando para tanto identificar as


strings que não devem ser traduzidas com :U (Exemplo: "CHOOSE":U).
Observação: O identificador :T no início de alguns comentários, é usado para a
tradução dos fontes dos templates para outros idiomas. Este identificador não
afeta em nada a funcionalidade do programa.

Tarefas
A seguir é apresentada a lista de tarefas para desenvolvimento do programa.
CAPÍTULO 6 Construindo o thinWindow 75

Preprocessors Inicialmente devem ser definidos os valores dos preprocessors padrão do


programa.
A seguir existe uma tabela que possui o nome dos preprocessors padrão e suas
descrições:
Preprocessor Descrição
Program Nome do programa – Formato (XX9999)
Version Versão do programa – Formato (9.99.99.999)
WindowType O valor Master indica que o programa é do tipo Janela
Mestre, e o valor Detail indica que o programa é do tipo
Janela Detalhe
Folder O valor YES indica que o programa terá folder
InitialPage Indica em qual página o programa irá iniciar
FolderLabels Descrição de cada uma das páginas do folder
pageNWidgets Nome dos widgets que devem ser habilitados na
inicialização do programa e estão nas frames fPageN, N
indica o número da página, podendo variar de 0 até 8

Observação O preprocessor Program refere-se ao nome com o qual o programa


está ou será cadastrado no menu.
Exemplo de código com o preenchimento dos preprocessadores:
&GLOBAL-DEFINE Program thinMaintenance
&GLOBAL-DEFINE Version 1.00.00.000

&GLOBAL-DEFINE WindowType Detail

&GLOBAL-DEFINE Folder YES


&GLOBAL-DEFINE InitialPage 1
&GLOBAL-DEFINE FolderLabels Local Default

&GLOBAL-DEFINE page0Widgets btOk btHelp


&GLOBAL-DEFINE page1Widgets

Páginas do folder O template, inicialmente, possui a definição de 2 (duas) páginas. Mas o


desenvolvedor pode retirá-las, a fim de manter somente a página principal, ou
acrescentar novas páginas, até o limite máximo de 8 (oito) páginas.
No entanto, se o programa não possuir as páginas fPage0 e fPage1, não é
possível inicializar o folder em tempo de execução (EPC). Por isso, aconselha-
se que, mesmo não sendo necessário o folder no momento do desenvolvimento
76

do programa, o programador conserve as páginas fPage0 e fPage1, alterando


apenas o pré-procesador Folder NO.
A frame principal (fPage0) somente pode ter sua altura alterada, o restante
das propriedades deve ser mantido. A altura deste é definida da forma a seguir:
 posicionamento da linha acrescido da altura dos frames das páginas.
Para cada página está relacionado um widget frame, possuindo a nomenclatura
fPage<PageNumber>. Para estes frames deve ser definida o fonte 1 e
seguido as regra de posicionamento e tamanho, descrita a seguir:
 devem estar posicionados na coluna 3.50;
 a linha na qual devem estar posicionados fica a 1.45 abaixo do último
widget da frame principal (fPage0);
 a largura não deve ser alterada (84.43);
 a altura é definida através da quantidade de widgets em linha acrescido de
0.25.
A imagem a seguir exibe como fica a janela do programa durante sua
construção:

Vale ressaltar que os labels das páginas não aparecem em tempo de


desenvolvimento, pois são criados durante a execução do programa. Por isso
faz-se necessário o espaço entre os frames das páginas e o último widget da
frame principal (fPage0).
CAPÍTULO 6 Construindo o thinWindow 77

Observação Para os campos do tipo fill-in’s, deve ser observado se o mesmo possue trigger
de "LEAVE"/"VALUE-CHANGED" e não tenha lupa como cursor do mouse ou um botão de
zoom na sua direita; ou possua trigger de "ENTRY". Caso o fill-in se encaixe em uma das
opções acima, deve ser efetuado o registro para o WebEnabler, conforme técnica Como registrar
campo do tipo Fill-in para o WebEnabler do Manual de Padrões.
O WebEnabler já registra automaticamente o evento de "LEAVE" para TODOS os fill-ins que
possuírem a lupa como cursor do mouse, ou que possuírem um botão de zoom na sua direita.
Portanto não é necessário efetuar o registro para esses fill-ins.

Disposição dos Quando for necessário fazer a inclusão de widgets (sejam campos ou widgets
widgets nas comuns) deve-se primeiramente selecionar o frame de trabalho. Para tanto usa-
páginas se o botão:

A tela a seguir é aberta, nesta deve selecionar-se a frame desejada e clicar-se


no botão que está indicado:

Após a seleção do frame de trabalho, deve-se fazer a inclusão dos widgets.


78

Os widgets devem ter algumas alterações em suas propriedades. Estas são


descritas a seguir:
 devem estar dispostos em linha, e caso necessário em colunas;
 para widgets do tipo fill-in, sua altura deve ser de 0.88;
 para widgets dos tipos combo-box, suas alturas devem ser de 1.00;
 para widgets dos tipos editores ou list-box ou radio-set, suas alturas devem
ser definidas pelo próprio desenvolvedor;
 a linha na qual os widgets que estão na primeira linha dos frames das
páginas, deve ser 1.17; os demais devem estar a distância de 1.00 do
widget anterior.

Considerações
Quando é construído um programa utilizando o template thinWindow
necessita-se realizar a implementação de lógicas auxiliares, tais como:
 programa de pesquisa de chave estrangeira;
 referência para campos de chave estrangeira.
Para tanto, deve-se utilizar o capítulo de Técnicas.
79

CAPÍTULO 7

Construindo o thinReport

Introdução Neste estão informações para que o desenvolvedor possa construir um


programa baseado no template thinReport. Este template deve ser utilizado
para construção de programas de Relatório, Importação e Exportação.
A seguir está um exemplo de programa de Relatório construído com o
template thinReport:
80

Vale ressaltar que toda a exemplificação será feita utilizando o banco de dados
Sports.
Características As características deste são:
 é uma janela do tipo detalhe, isto é, sem menu de barra e moldura,
simulando uma caixa de diálogo;
 o botão 'Executar' tem como função executar toda a parametrização
realizada nos Folders;
 o botão 'Fechar' do frame sai da tela;
 o botão 'Ajuda' é responsável por chamar o help do programa;
 Seleção: tudo que é faixa;
 Classificação: Radio-set com as opções;
 Parâmetros: com exceção da faixa, as outras informações que o usuário
digita;
 Digitação: browse updatable.
 o gerenciamento das páginas do folder é feito pelo programa
objects/thinFolder.w;
 uma das opções de saída do relatório é o formato RTF (Rich Text Format).
 faz uso do sistema de tradução de .R, bastando para tanto identificar as
strings que não devem ser traduzidas com :U (Exemplo: "CHOOSE":U).
Observação: O identificador :T no início de alguns comentários, é usado para a
tradução dos fontes dos templates para outros idiomas. Este identificador não
afeta em nada a funcionalidade do programa.

Tarefas
A seguir é apresentada a lista de tarefas para desenvolvimento do programa.
Observar o que são tarefas para programas de Relatório, Importação e
Exportação.
Preprocessors Inicialmente devem ser definidos os valores dos preprocessors padrões do
programa.
CAPÍTULO 7 Construindo o thinReport 81

A seguir é apresentada tabela com os nomes dos preprocessors padrões e suas


descrições:
Preprocessor Descrição
Program Nome do programa – Formato (XX9999)
Version Versão do programa – Formato (9.99.99.999)
VersionLayout Versão do Layout – Formato (999)
Folder O valor YES indica que o programa terá folder
InitialPage Indica em qual página o programa irá iniciar
FolderLabels Descrição de cada uma das páginas do folder
PGLAY Indica se a página de Layout estará disponível
PGSEL Indica se a página de Seleção estará disonível
PGCLA Indica se a página de Classificação estará disponível
PGPAR Indica se a página de Parâmetros estará disponível
PGDIG Indica se a página de Digitação estará disponível
PGIMP Indica se a página de Impressão estará disponível
PGLOG Indica se a página de Log estará disponível
RTF Indica se a opção de saída para RTF estará disponível
Page0Widgets Lista de widgets disponíveis na página 0
Page1Widgets Lista de widgets disponíveis na página 1
Page2Widgets Lista de widgets disponíveis na página 2
Page3Widgets Lista de widgets disponíveis na página 3
Page4Widgets Lista de widgets disponíveis na página 4
Page5Widgets Lista de widgets disponíveis na página 5
Page6Widgets Lista de widgets disponíveis na página 6
Page7Widgets Lista de widgets disponíveis na página 7
Page8Widgets Lista de widgets disponíveis na página 8
Page0Text Lista de textos disponíveis na página 0
Page1Text Lista de textos disponíveis na página 1
Page2Text Lista de textos disponíveis na página 2
Page3Text Lista de textos disponíveis na página 3
Page4Text Lista de textos disponíveis na página 4
Page5Text Lista de textos disponíveis na página 5
Page6Text Lista de textos disponíveis na página 6
Page7Text Lista de textos disponíveis na página 7
Page8Text Lista de textos disponíveis na página 8
Page0Fields Lista de variáveis disponíveis na página 0
Page1Fields Lista de variáveis disponíveis na página 1
Page2Fields Lista de variáveis disponíveis na página 2
Page3Fields Lista de variáveis disponíveis na página 3
82

Preprocessor Descrição
Page4Fields Lista de variáveis disponíveis na página 4
Page5Fields Lista de variáveis disponíveis na página 5
Page6Fields Lista de variáveis disponíveis na página 6
Page7Fields Lista de variáveis disponíveis na página 7
Page8Fields Lista de variáveis disponíveis na página 8

Observação O preprocessor Program refere-se ao nome com o qual o programa


está ou será cadastrado no menu.
Exemplo de código com o preenchimento dos preprocessors:
/* Preprocessors Definitions --- */
&GLOBAL-DEFINE Program thinReport
&GLOBAL-DEFINE Version 1.00.00.000
&GLOBAL-DEFINE VersionLayout

&GLOBAL-DEFINE Folder YES


&GLOBAL-DEFINE InitialPage 1
&GLOBAL-DEFINE FolderLabels Seleção,Classificação,Parâmetro,
Digitação,Impressão

&GLOBAL-DEFINE PGLAY NO
&GLOBAL-DEFINE PGSEL YES
&GLOBAL-DEFINE PGCLA YES
&GLOBAL-DEFINE PGPAR YES
&GLOBAL-DEFINE PGDIG YES
&GLOBAL-DEFINE PGIMP YES
&GLOBAL-DEFINE PGLOG NO

&GLOBAL-DEFINE RTF YES

&GLOBAL-DEFINE page0Widgets btOk ~


btCancel ~
btHelp2
&GLOBAL-DEFINE page1Widgets
&GLOBAL-DEFINE page2Widgets
&GLOBAL-DEFINE page3Widgets rsClassif
&GLOBAL-DEFINE page4Widgets lParameter ~
btInputFile
&GLOBAL-DEFINE page5Widgets brDigita ~
btAdd ~
btUpdate ~
btDelete ~
btSave ~
btOpen
&GLOBAL-DEFINE page6Widgets rsDestiny ~
btConfigImpr ~
btFile ~
CAPÍTULO 7 Construindo o thinReport 83

rsExecution
&GLOBAL-DEFINE page7Widgets
&GLOBAL-DEFINE page8Widgets

&GLOBAL-DEFINE page0Text
&GLOBAL-DEFINE page1Text
&GLOBAL-DEFINE page2Text
&GLOBAL-DEFINE page3Text
&GLOBAL-DEFINE page4Text text-entrada
&GLOBAL-DEFINE page5Text
&GLOBAL-DEFINE page6Text text-destino text-modo
&GLOBAL-DEFINE page7Text
&GLOBAL-DEFINE page8Text

&GLOBAL-DEFINE page1Fields
&GLOBAL-DEFINE page2Fields cIniField cEndField
&GLOBAL-DEFINE page3Fields
&GLOBAL-DEFINE page4Fields cInputFile
&GLOBAL-DEFINE page5Fields
&GLOBAL-DEFINE page6Fields cFile
&GLOBAL-DEFINE page7Fields
&GLOBAL-DEFINE page8Fields

Páginas do folder O template, inicialmente, possui a definição de 7 (sete) páginas. Mas o


desenvolvedor pode retirá-las, a fim de manter somente as páginas necessárias.
A ordem e nomenclatura original das páginas são:
fPage0 - Principal
fPage1 - Layout
fPage2 - Seleção
fPage3 - Classificação
fPage4 - Parâmetro
fPage5 - Digitação
fPage6 - Impressão
fPage7 - Log
A frame principal (fPage0) somente pode ter sua altura alterada, o restante
das propriedades deve ser mantido. A altura desta é definida da forma a seguir:
 posicionamento da linha acrescido da altura dos frames das páginas.
84

Para cada página está relacionado um widget frame, possuindo a nomenclatura


fPage<PageNumber>. Para estes frames deve ser definida o fonte 1 e
seguido as regra de posicionamento e tamanho, descrita a seguir:
 devem estar posicionados na coluna 3.50;
 a linha na qual devem estar posicionados fica a 1.45 abaixo do último
widget da frame principal (fPage0);
 a largura não deve ser alterada (84.43);
 a altura é definida através da quantidade de widgets em linha acrescido de
0.25.
A imagem a seguir exibe como fica a janela do programa durante sua
construção:

Vale ressaltar que os labels das páginas não aparecem em tempo de


desenvolvimento, pois são criados durante a execução do programa. Por isso
faz-se necessário o espaço entre os frames das páginas e o último widget da
frame principal (fPage0).
CAPÍTULO 7 Construindo o thinReport 85

Observação Para os campos do tipo fill-in’s, deve ser observado se o mesmo possue trigger
de "LEAVE"/"VALUE-CHANGED" e não tenha lupa como cursor do mouse ou um botão de
zoom na sua direita; ou possua trigger de "ENTRY". Caso o fill-in se encaixe em uma das
opções acima, deve ser efetuado o registro para o WebEnabler, conforme técnica Como registrar
campo do tipo Fill-in para o WebEnabler do Manual de Padrões.
O WebEnabler já registra automaticamente o evento de "LEAVE" para TODOS os fill-ins que
possuírem a lupa como cursor do mouse, ou que possuírem um botão de zoom na sua direita.
Portanto não é necessário efetuar o registro para esses fill-ins.

Disposição dos Quando for necessário fazer a inclusão de widgets (sejam campos ou widgets
widgets nas comuns) deve-se primeiramente selecionar o frame de trabalho. Para tanto usa-
páginas se o botão:

A tela a seguir é aberta, nesta deve selecionar-se a frame desejada e clicar-se


no botão que está indicado:

Após a seleção do frame de trabalho, deve-se fazer a inclusão dos widgets.


86

Os widgets devem ter algumas alterações em suas propriedades. Estas são


descritas a seguir:
 devem estar dispostos em linha, e caso necessário em colunas;
 para widgets do tipo fill-in, sua altura deve ser de 0.88;
 para widgets dos tipos combo-box, suas alturas devem ser de 1.00;
 para widgets dos tipos editores ou list-box ou radio-set, suas alturas devem
ser definidas pelo próprio desenvolvedor;
 a linha na qual os widgets que estão na primeira linha dos frames das
páginas, deve ser 1.17; os demais devem estar a distância de 1.00 do
widget anterior.

Preparação do 1. Verificar quais páginas é necessário ao programa.


Programa 2. Eliminar as frames das páginas desnecessárias com base na tabela acima.
(Interface)
3. Em 'Definitions' informar “NO” para os pré-processadores referentes as
páginas que não serão utilizadas, como no exemplo a seguir. Retirar o
valor dos pré-processadores (PageNField, PageNWidgets, PageNText) das
páginas desnecessárias, assim como o pré-processador de label do folder
(FolderLabels):
&GLOBAL-DEFINE PGLAY NO
&GLOBAL-DEFINE PGSEL YES
&GLOBAL-DEFINE PGCLA YES
&GLOBAL-DEFINE PGPAR YES
&GLOBAL-DEFINE PGDIG YES
&GLOBAL-DEFINE PGIMP YES
&GLOBAL-DEFINE PGLOG NO

4. Para a opção de saída do relatório para o formato RTF não é necessária


nenhuma codificação adicional, apenas basta informar em ‘Definitions’ o
valor do respectivo préprocessador para YES conforme exemplo:
&GLOBAL-DEFINE RTF YES

Também é possível informar na inicialização do programa um arquivo de


modelo padrão para o relatório, desta forma não deixando obrigatório que
o usuário tenha que informá-lo no momento da impressão. Para isto basta
adicionar a linha abaixo no Main-block do programa, logo após a chamada
da include:
CAPÍTULO 7 Construindo o thinReport 87

{report/MainBlock.i}
ASSIGN cModelRtf:SCREEN-VALUE IN FRAME fpage6 =
SEARCH("<pasta>\<modelo.rtf>").

onde:
<pasta> = sub-pasta aonde se encontra o arquivo de modelo no propath
<modelo.rtf> = arquivo que contém o modelo no formato rtf

Página de Layout Somente faz-se necessário alterar a página de Layout nos casos onde não se
desejar o box da frame. Para tanto, deve-se acessar as propriedades da frame e
selecionar a opção NO-BOX. Esta página é obrigatória para os programas de
Importação e Exportação.
Criar um arquivo que contenha o layout de importação, nos padrões do
Produto Datasul-EMS.Este arquivo tem o seguinte nome e path:
LAYOUT/LOXX9999.001..

Página de Seleção 1. A sugestão é criar como 'Database Fields' e após convertê-los para
variáveis para obter automaticamente os labels, formatos e tamanhos do
dicionário de dados.
2. Corrigir os 'initial values' das variáveis de inicial e final.

Página de 1. Redefinir o 'list-items' do radio-set rs-classif , com as opções de


Classificação classificação de seu relatório;
2. Se necessário adicionar mais opções de classificação.

Página de Esta página é obrigatória para programas de Importação e Exportação.


Parâmetros 1. Colocar as variáveis necessárias na representação desejada (radio-set,
toggle-box, fill-in), definindo label, formato, initial e help para as mesmas.
2. Se necessário, retirar a variável que receberá o arquivo de importação,
bem como o retângulo e o botão relacionado a essa fill-in. Este campo é
obrigatório para programas de Importação e Exportação. É nesse campo
que o usuário irá informar o arquivo a ser importado (Importação) ou o
destino para o arquivo que será gerado (Exportação). Para programas de
88

Exportação, é preciso comentar, na pi-executar, a validação feita para


verificar a existência do arquivo informado nesse campo, conforme mostra
o exemplo a seguir:
/* assign file-info:file-name = input frame fPage4 cInputFile. */
/* if file-info:pathname = ? and */
/* input frame fPage7 rsExecution = 1 then do: */
/* run utp/ut-msgs.p (input "SHOW":U, */
/* input 326, */
/* input cInputFile). */
/* apply "ENTRY":U to cInputFile in frame fPage4. */
/* return error. */
/* end. */

Página de 1. Em 'Definitions', corrigir a definição da temp-table de digitação tt-digita


Digitação inserindo os campos necessários;
2. Em 'Section Editor', para o objeto browse br-digita adaptar os seguintes
gatilhos para a nova definição da temp-table tt-digita e outras
necessidades:
'Display': define os campos da temp-table a serem apresentados e quais
devem ficar habilitados;
'Row-entry': determina valores iniciais para os campos da temp-table na
inclusão de novas linhas, exceto quando se trata da primeira linha do
browse;
'Row-leave': salva as alterações feitas pelo usuário.
3. Ainda em 'Section Editor', mas para os botões btAdd e btUpdate, adaptar
os seus gatilhos de 'Choose', na linha que aplica um evento 'Entry', sobre o
primeiro campo habilitado no browse;
4. Todas as validações do browse brDigita devem ser feitas na procedure
piExecute no local indicado pelo comentário. Opcionalmente, os gatilhos
de 'leave' (para atributos de referência), 'f5' e 'mouse-select-dblclick' (para
acionamento do zoom), para as colunas do browse podem ser necessários.
Neste caso, tais gatilhos devem ser codificados "à mão", no início do
'Main Block' do programa.

Página de A página de Impressão não é necessária que se tenha qualquer função


Impressão adicional para o seu correto funcionamento. Esta página somente deve ser
CAPÍTULO 7 Construindo o thinReport 89

utilizada para programas de Relatório, para programas de Importação e


Exportação não.

Página de Log Esta página é obrigatória para programas de Importação e Exportação. Para
programas de Relatório não utilizar esta página. Para programas de
Exportação, retirar o campo rsAll, o retângulo e o texto Imprime.
Gravação e 1. Em 'Definitions' implementar os campos de parâmetros e seleção na
validação dos definição da temp-table tt-param.
parâmetros 2. Na procedure 'piExecute', colocar as validações necessárias às opções do
usuário para execução do relatório no local indicado pelo comentário,
lembrando que elas devem apresentar uma mensagem de erro cadastrada,
posicionar na página com problemas, colocando o focus no campo com
problemas.
Exemplo if input frame f-pg-par i-nr-nivel > 19 then do:
run SetFolder IN hFolder (INPUT 2).
run utp/ut-msgs.p (input "show",
input 73,
input " ").
apply 'entry' to i-nr-nivel in frame f-pg-par.
return error.
end.

3. Na procedure 'piExecute', no local indicado pelo comentário, colocar a


lógica de gravação dos parâmetros e seleção na temp-table tt-param.
4. Ainda na procedure 'pi-executar', substituir na chamada do include
{report/i-rprun.i} a literal 'XXP/XX9999RP.P' pelo programa que deve
imprimir o relatório.

Dicas para criação O programa de execução do relatório (rp.p) é um programa procedural sem
do programa RP.P qualquer tipo de interface com o usuário, exceto pela própria
de Relatório impressão/visualização do relatório e pela caixa de acompanhamento de
execução (ut-acomp/ut-perc) quando necessário. Da mesma forma, nenhum
programa chamado a partir de um rp.p não deve possuir qualquer tipo de
interface. Todas as validações ou informações com necessidade de intervenção
do usuário devem ser tratadas pelo programa .w que o chama.
90

1. Copiar a definição das temp-tables tt-param e tt-digita (esta última se


houver digitação) do programa de interface (.W) para o programa que deve
gerar o relatório (rp.p);
2. Utilizar um stream padrão definido como STR-RP, para impressão do
relatório, deve-se passar o parâmetro &stream com o nome da stream para
os includes i-rpcab.i, i-rpcb80, i-rpc256.i, i-rpout.i e i-rpclo.i. Para
programas de Importação e Exportação definir outro stream para a
entrada/saída dos dados.
Exemplo {include/i-rpcab.i &stream = "str-rp"}
{include/i-rpcb80.i &stream = "str-rp"}
{include/i-rpc256.i &stream = "str-rp"}
{include/i-rpout.i &stream = "stream str-rp"}
{include/i-rpclo.i &stream = "stream str-rp"}.

3. Nas seleções, ao invés de utilizar a palavra "à", para dar idéia de faixa,
substituí-la pelos caracteres "|< >|" semelhantes as imagens utilizadas na
tela de seleção, e que não necessitam ser traduzidos.
4. Em todos os forms/frames de impressão deve-se colocar a cláusula stream-
io.
5. Para utilizar a funcionalidade de impressão para arquivo RTF:
5.1. definir o préprocessador conforme abaixo:
&GLOBAL-DEFINE RTF YES
5.2. definir o préprocessador abaixo setando o tamanho da página:
&SCOPED-DEFINE pagesize N
N é o número de linhas por página e por default seu valor é 42.
Este número deve ser ajustado para cada relatório conforme o tamanho
do modelo RTF que vai ser utilizado. Caso este tamanho não esteja
correto ocorrerá problema na quebra da página.
5.3. a definição da temp-table tt-param deve ser idêntica a definição da
mesma no programa de interface.
5.4. condicionar o VIEW das frames de cabeçalho/rodapé no início do
programa, para que quando o destino for para RTF as mesmas não
sejam apresentadas. Segue exemplo abaixo:
IF tt-param.destino <> 4 THEN DO:
VIEW STREAM str-rp FRAME f-cabec.
CAPÍTULO 7 Construindo o thinReport 91

VIEW STREAM str-rp FRAME f-rodape.


END.
Exemplo de um /* include de controle de versão */
programa RP.P de {include/i-prgvrs.i SP0014RP 1.00.00.000}
Relatório
/* préprocessador para ativar ou não a saída para RTF */
&GLOBAL-DEFINE RTF YES
/* préprocessador para setar o tamanho da página */
&SCOPED-DEFINE pagesize 43
/* definição das temp-tables para recebimento de parâmetros */
DEFINE TEMP-TABLE tt-param NO-UNDO
FIELD destino AS INTEGER
FIELD arquivo AS CHARACTER FORMAT "x(35)"
FIELD usuario AS CHARACTER FORMAT "x(12)"
FIELD data-exec AS DATE
FIELD hora-exec AS INTEGER
FIELD classifica AS INTEGER
FIELD desc-classifica AS CHARACTER FORMAT "x(40)"
FIELD modelo-rtf AS CHARACTER FORMAT "x(35)" /*
arquivo modelo para RTF */
FIELD ini-cust-num LIKE customer.cust-num /* campo
página seleção */
FIELD fim-cust-num LIKE customer.cust-num /* campo
página seleção */
FIELD sales-rep LIKE salesrep.sales-rep /* campo
página parâmetros */
.

DEFINE TEMP-TABLE tt-raw-digita NO-UNDO


FIELD raw-digita AS RAW.

/* recebimento de parâmetros */
DEFINE INPUT PARAMETER raw-param AS RAW NO-UNDO.
92

DEFINE INPUT PARAMETER TABLE FOR tt-raw-digita.

CREATE tt-param.
RAW-TRANSFER raw-param TO tt-param.

/* include padrão para variáveis de relatório */


{include/i-rpvar.i}

/* definição de variáveis */
DEFINE VARIABLE h-acomp AS HANDLE NO-UNDO.

/* definição de frames do relatório */


FORM /* usar ordenado por order-num */
Order.Order-num
Order.Cust-Num
Order.Order-Date
Order.Promise-Date
Order.Sales-Rep
Order.Ship-Date
Order.Carrier
WITH FRAME f-order DOWN STREAM-IO.
FORM /* usar ordenado por cust-num */
Order.Cust-Num
Order.Order-num
Order.Order-Date
Order.Promise-Date
Order.Sales-Rep
Order.Ship-Date
Order.Carrier
WITH FRAME f-customer DOWN stream-io.
CAPÍTULO 7 Construindo o thinReport 93

/* include padrão para output de relatórios */


{include/i-rpout.i &STREAM="stream str-rp"}

/* include com a definição da frame de cabeçalho e rodapé */


{include/i-rpcab.i &STREAM="str-rp"}

/* bloco principal do programa */


ASSIGN c-programa = "SP0014RP"
c-versao = "1.00"
c-revisao = ".00.000"
c-empresa = "Empresa Teste"
c-sistema = "Sports"
c-titulo-relat = "Listagem Order".

/* para não visualizar cabeçalho/rodapé em saída RTF */


IF tt-param.destino <> 4 THEN DO:
VIEW STREAM str-rp FRAME f-cabec.
VIEW STREAM str-rp FRAME f-rodape.
END.

/* executando de forma persistente o utilitário de


acompanhamento */
RUN utp/ut-acomp.p PERSISTENT SET h-acomp.
{utp/ut-liter.i Imprimindo *}
RUN pi-inicializar IN h-acomp (INPUT RETURN-VALUE).

/* corpo do relatório */
IF tt-param.classifica = 1 THEN DO:
FOR EACH order WHERE
order.sales-rep = tt-param.sales-rep AND
94

order.cust-num >= tt-param.ini-cust-num AND


order.cust-num <= tt-param.fim-cust-num
NO-LOCK
ON STOP UNDO, LEAVE:
RUN pi-acompanhar IN h-acomp (INPUT STRING(order.order-
num)).
DISPLAY STREAM str-rp
Order.Cust-Num
Order.Order-num
Order.Order-Date
Order.Promise-Date
Order.Sales-Rep
Order.Ship-Date
Order.Carrier WITH FRAME f-order.
DOWN STREAM str-rp WITH FRAME f-order.
END.
END.
ELSE DO:
FOR EACH order WHERE
order.sales-rep = tt-param.sales-rep AND
order.cust-num >= tt-param.ini-cust-num AND
order.cust-num <= tt-param.fim-cust-num
NO-LOCK
BY order.cust-num
ON STOP UNDO, LEAVE:
RUN pi-acompanhar IN h-acomp (INPUT STRING(order.order-
num)).
DISPLAY STREAM str-rp
Order.Cust-Num
Order.Order-num
Order.Order-Date
Order.Promise-Date
CAPÍTULO 7 Construindo o thinReport 95

Order.Sales-Rep
Order.Ship-Date
Order.Carrier WITH FRAME f-customer.
DOWN STREAM str-rp WITH FRAME f-customer.
END.
END.

/*fechamento do output do relatório*/


{include/i-rpclo.i &STREAM="stream str-rp"}
RUN pi-finalizar IN h-acomp.
RETURN "OK":U.

/* include de controle de versão */


Exemplo de
programa RP.P de {include/i-prgvrs.i XX9999RP 1.00.00.000}
Importação /* definição das temp-tables para recebimento de parâmetros */
define temp-table tt-param no-undo
field destino as integer
field arquivo as char format "x(35)"
field arq-entrada as char format "x(35)"
field arq-destino as char format "x(35)"
field usuario as char format "x(12)"
field data-exec as date
field hora-exec as INTEGER.

def temp-table tt-raw-digita


field raw-digita as raw.

/* recebimento de parâmetros */
def input parameter raw-param as raw no-undo.
def input parameter TABLE for tt-raw-digita.

create tt-param.
RAW-TRANSFER raw-param to tt-param NO-ERROR.

/* include padrão para variáveis para o log */


96

{include/i-rpvar.i}

/* definição de variáveis e streams */


def stream s-imp.
def var h-acomp as handle no-undo.
def var c-linha as char no-undo.
def var i-cust as int no-undo.

/* definição de frames do log */

/* include padrão para output de log */


{include/i-rpout.i &STREAM="stream str-rp" &TOFILE=tt-param.arq-
destino}

/* include com a definição da frame de cabeçalho e rodapé */


{include/i-rpcab.i &STREAM="str-rp"}

/* bloco principal do programa */


assign c-programa = "IM0001RP"
c-versao = "1.00"
c-revisao = ".00.000"
c-empresa = "Empresa Teste"
c-sistema = 'Sports'
c-titulo-relat = "Importação de Customer".

view stream str-rp frame f-cabec.


view stream str-rp frame f-rodape.
run utp/ut-acomp.p persistent set h-acomp.
{utp/ut-liter.i Importando *}

run pi-inicializar in h-acomp (input RETURN-VALUE).

/* define o arquivo de entrada informando na página de parâmetros */


input stream s-imp FROM value(tt-param.arq-entrada).

/* bloco principal do programa */


repeat on stop undo, leave:
CAPÍTULO 7 Construindo o thinReport 97

import stream s-imp unformatted c-linha.


run pi-acompanhar in h-acomp (input c-linha).
assign i-cust = integer(substring(c-linha,1,5)).
find customer where customer.cust-num = i-cust no-lock.
if not avail customer then do:
create customer.
assign customer.cust-num = i-cust
customer.name = substring(c-linha,5).
end.
ELSE DO:
PUT STREAM str-rp "Cliente " i-cust " já cadastrado!" SKIP.
END.
end.

input stream s-imp close.

/* fechamento do output do log */


{include/i-rpclo.i &STREAM="stream str-rp"}

run pi-finalizar in h-acomp.

return "Ok":U.

/* include de controle de versão */


Exemplo programa
RP.P de {include/i-prgvrs.i EX0001RP 1.00.00.000}
Exportação
/* definição das temp-tables para recebimento de parâmetros */
define temp-table tt-param no-undo
field destino as integer
field arq-saida as char format "x(35)"
field arq-destino as char format "x(35)"
field usuario as char format "x(12)"
field data-exec as date
field hora-exec as integer
FIELD cust-ini AS INTEGER
FIELD cust-fim AS INTEGER.
98

def temp-table tt-raw-digita


field raw-digita as raw.

/* recebimento de parâmetros */
def input parameter raw-param as raw no-undo.
def input parameter TABLE for tt-raw-digita.

create tt-param.
RAW-TRANSFER raw-param to tt-param NO-ERROR.

/* include padrão para variáveis para o log */


{include/i-rpvar.i}

/* definição de variáveis e streams */


def stream s-exp.
def var h-acomp as handle no-undo.

/* definição de frames do log */

/* include padrão para output de log */


{include/i-rpout.i &STREAM="stream str-rp" &TOFILE=tt-param.arq-
destino}

/* include com a definição da frame de cabeçalho e rodapé */


{include/i-rpcab.i &STREAM="str-rp"}

/* bloco principal do programa */


assign c-programa = "EX0001RP"
c-versao = "1.00"
c-revisao = ".00.000"
c-empresa = "Empresa Teste"
c-sistema = 'Sports'
c-titulo-relat = "Exportação dos Registros da Tabela
Customer".
CAPÍTULO 7 Construindo o thinReport 99

view stream str-rp frame f-cabec.


view stream str-rp frame f-rodape.

run utp/ut-acomp.p persistent set h-acomp.


{utp/ut-liter.i Exportando *}

run pi-inicializar in h-acomp (input RETURN-VALUE).

/* define a saída para o arquivo de saída informando na página de


parâmetros */
output stream s-exp TO value(tt-param.arq-saida).

/* bloco principal do programa */


for each customer WHERE
customer.cust-num >= tt-param.cust-ini and
customer.cust-num <= tt-param.cust-fim on stop undo, leave:
run pi-acompanhar in h-acomp (input string(customer.cust-
num)).
put stream s-exp unformatted string(customer.cust, "99999")
string(customer.name,"x(20)")
skip.
end.

output stream s-exp close.

PUT STREAM str-rp "Exportação concluída com sucesso!" SKIP.

/*fechamento do output do log */


{include/i-rpclo.i &STREAM="stream str-rp"}

run pi-finalizar in h-acomp.

return "Ok":U.
100

Considerações
Quando é construído um programa utilizando o template thinReport necessita-
se realizar a implementação de lógicas auxiliares, tais como:
 programa de pesquisa de chave estrangeira;
 referência para campos de chave estrangeira. Para tanto, deve-se utilizar o
capítulo de Técnicas.
CAPÍTULO 7 Construindo o thinReport 101

Como migrar relatórios antigos para RTF


Esta técnica permite gerar a saída do relatório em um arquivo RTF nos
programas que foram criados antes da alteração que incluiu esta funcionalidae
no template.

 Em Definitions, acrescentar após &GLOBAL-DEFINE PGIMP:


&GLOBAL-DEFINE RTF YES

 Incluir na definição do préprocessador page6Text os campos


text-rtf e text-ModelRtf.
Exemplo:
&GLOBAL-DEFINE page6Text text-destino text-modo text-rtf
text-ModelRtf

 Incluir na definição do préprocessador page6Fields o campo


cModelRtf.
Exemplo:
&GLOBAL-DEFINE page6Fields cFile cModelRtf

 Incluir na definição do préprocessador page6Widgets os campo


l-habilitaRtf e btModelRtf.
Exemplo:
&GLOBAL-DEFINE page6Widgets rsDestiny ~
btConfigImpr ~
btFile ~
rsExecution ~
l-habilitaRtf ~
btModelRtf

 Na definição da temp-table TT-PARAM, acrescente o seguinte


campo:
102

field modelo-rtf as char format "x(35)"


field l-habilitaRtf as LOG

 Inclua após a definição da variável local c-terminal:


def var c-rtf as char no-undo.
DEF VAR c-modelo-default AS CHAR NO-UNDO.
DEFINE SHARED VARIABLE hWenController AS HANDLE NO-UNDO.

 Incluir o seguinte código na procedure afterInitializeInterface:


&IF "{&RTF}":U = "YES":U &THEN
IF VALID-HANDLE(hWenController) THEN DO:
ASSIGN l-habilitaRtf:sensitive IN FRAME fPage6 = NO
l-habilitaRtf:SCREEN-VALUE IN FRAME fPage6 = "No"
l-habilitaRtf = NO.
END.
RUN pi-habilitaRtf.

&endif

 Para criar os componentes utilizados pela funcionalidade de RTF é


necessário abrir o programa que está sendo alterado no procedure editor e
executar os passos abaixo:
 Após a definição do botão bt-config-impr(“DEFINE BUTTON bt-
config-impr”) inserir o seguinte código:
DEFINE BUTTON btModelRtf
IMAGE-UP FILE "image\im-sea":U
IMAGE-INSENSITIVE FILE "image\ii-sea":U
LABEL ""
SIZE 4 BY 1.
 Após a definição da variável cFile(“DEFINE VARIABLE cFile AS
CHARACTER”) inserir o seguinte código:
DEFINE VARIABLE cModelRtf AS CHARACTER
VIEW-AS EDITOR MAX-CHARS 256
CAPÍTULO 7 Construindo o thinReport 103

SIZE 40 BY .88
BGCOLOR 15 NO-UNDO.
 Após a definição da variável text-destino(“DEFINE VARIABLE text-
destino AS CHARACTER”) inserir o seguinte código:
DEFINE VARIABLE text-ModelRtf AS CHARACTER FORMAT
"X(256)":U INITIAL "Modelo:"
VIEW-AS TEXT
SIZE 10 BY .67 NO-UNDO.
 Após a definição da variável text-modo(“DEFINE VARIABLE text-
modo AS CHARACTER”) inserir o seguinte código:
DEFINE VARIABLE text-rtf AS CHARACTER FORMAT
"X(256)":U INITIAL "Rich Text Format(RTF)"
VIEW-AS TEXT
SIZE 16 BY .67 NO-UNDO.
 Após a definição do retângulo rect-9 (“DEFINE RECTANGLE
RECT-9”) inserir o seguinte código:
DEFINE RECTANGLE rect-rtf
EDGE-PIXELS 2 GRAPHIC-EDGE NO-FILL
SIZE 46.14 BY 3.21.

DEFINE VARIABLE l-habilitaRtf AS LOGICAL INITIAL no


LABEL "RTF"
VIEW-AS TOGGLE-BOX
SIZE 44 BY 1.08 NO-UNDO.

 Na definição da frame fPage6 (“DEFINE FRAME fPage6”) alterar os


seguintes campos:
l-habilitaRtf AT ROW 5.58 COL 3
cModelRtf AT ROW 7.29 COL 3 HELP
"Nome do arquivo de modelo do relatório" NO-LABEL
btModelRtf AT ROW 7.29 COL 43 HELP
"Escolha do nome do arquivo"
text-rtf AT ROW 5 COL 1.14 COLON-ALIGNED NO-LABEL
104

text-ModelRtf AT ROW 6.54 COL 1 COLON-ALIGNED NO-


LABEL
rsExecution AT ROW 9.58 COL 2.86 HELP
"Modo de Execução" NO-LABEL
text-modo AT ROW 8.75 COL 1.14 COLON-ALIGNED NO-
LABEL
rect-rtf AT ROW 5.29 COL 2
RECT-9 AT ROW 9.04 COL 2

 Abrir o programa no AppBuilder e alterar a trigger de


“VALUE_CHANGED” do componente l-habilitaRTF, colocando o
seguinte código:
DO:
&IF "{&RTF}":U = "YES":U &THEN
RUN pi-habilitaRtf.
&endif
END.

 Substituir o código da trigger de “VALUE-CHANGED” do componente


rsDestiny pelo código abaixo:
DO:
do with frame fPage6:
case self:screen-value:
when "1":U then do:
assign cFile:sensitive = no
cFile:visible = yes
btFile:visible = no
btConfigImpr:visible = yes
&IF "{&RTF}":U = "YES":U &THEN
l-habilitaRtf:sensitive = NO
l-habilitaRtf:SCREEN-VALUE IN FRAME fPage6
= "No"
CAPÍTULO 7 Construindo o thinReport 105

l-habilitaRtf = NO
&endif
.
end.
when "2":U then do:
assign cFile:sensitive = yes
cFile:visible = yes
btFile:visible = yes
btConfigImpr:visible = no
&IF "{&RTF}":U = "YES":U &THEN
l-habilitaRtf:sensitive = YES
&endif
.
end.
when "3":U then do:
assign cFile:visible = no
cFile:sensitive = no
btFile:visible = no
btConfigImpr:visible = no
&IF "{&RTF}":U = "YES":U &THEN
l-habilitaRtf:sensitive = YES
&endif
.
&IF "{&RTF}":U = "YES":U &THEN
IF VALID-HANDLE(hWenController) THEN DO:
ASSIGN l-habilitaRtf:sensitive = NO
l-habilitaRtf:SCREEN-VALUE IN FRAME
fPage6 = "No"
l-habilitaRtf = NO.
END.
&endif
END.
106

end case.
end.
&IF "{&RTF}":U = "YES":U &THEN
RUN pi-habilitaRtf.
&endif
END.

 Alterar a trigger de “CHOOSE” do botão btModelRtf para o seguinte


código:
DO:
def var cFile as char no-undo.
def var l-ok as logical no-undo.

assign cModelRtf = replace(input frame {&frame-name}


cModelRtf, "/", "\").
SYSTEM-DIALOG GET-FILE cFile
FILTERS "*.rtf" "*.rtf",
"*.*" "*.*"
DEFAULT-EXTENSION "rtf"
INITIAL-DIR "modelos"
MUST-EXIST
USE-FILENAME
UPDATE l-ok.
if l-ok = yes then
assign cModelRtf:screen-value in frame {&frame-name}
= replace(cFile, "\", "/").
END.

 Na procedure piExecute após o teste de validação do arquivo


informado(“if input frame f-pg-imp rs-destino = 2 and input frame f-pg-
imp rs-execucao = 1 then do:”) inserir o código abaixo que é responsável
por validar o modelo informado:
&IF "{&RTF}":U = "YES":U &THEN
CAPÍTULO 7 Construindo o thinReport 107

IF ( input frame fPage6 cModelRtf = "" AND


input frame fPage6 l-habilitaRtf = YES ) OR
( SEARCH(INPUT FRAME fPage6 cModelRtf) = ? AND
input frame fPage6 rsExecution = 1 AND
input frame fPage6 l-habilitaRtf = YES )
THEN DO:
run utp/ut-msgs.p (input "show":U, input 73, input
"":U).
return error.
END.
&endif

 Na procedure piExecute, ao criar o registro na tt-param, acrescente o


seguinte trecho de código no comando assign:
&IF "{&RTF}":U = "YES":U &THEN
tt-param.modelo-rtf = INPUT FRAME fPage6 cModelRtf
tt-param.l-habilitaRtf = INPUT FRAME fPage6 l-
habilitaRtf
&endif

 Alterações no Programa RP:

1. Verificar se existe a definição dos préprocessadores:


&GLOBAL-DEFINE RTF YES
&SCOPED-DEFINE pagesize N
N é o número de linhas por página e por default seu valor é 42. Este
número deve ser ajustado para cada relatório conforme o tamanho do
modelo RTF que vai ser utilizado. Caso este tamanho não esteja
correto ocorrerá problema na quebra da página.
2. Na definição da temp-table tt-param, acrescente oscampos
field modelo-rtf as char format "x(35)" e
field l-habilitaRtf as LOG.
108

3. Condicionar o VIEW das FRAMES no início do programa:


IF tt-param.l-habilitaRTF <> YES THEN DO:
VIEW STREAM str-rp FRAME f-cabec.
VIEW STREAM str-rp FRAME f-rodape.
END.

4. Verificar se as includes i-rpcab.i, i-rpcb80, i-rpc256.i, i-rpout.i e i-


rpclo.i utilizam o stream padrão conforme exemplo:
{include/i-rpcab.i &stream = "str-rp"}
{include/i-rpcb80.i &stream = "str-rp"}
{include/i-rpc256.i &stream = "str-rp"}
{include/i-rpout.i &stream = "stream str-rp"}
{include/i-rpclo.i &stream = "stream str-rp"}.

5. Alterar os comandos DISPLAY para DISPLAY STREAM str-rp.


CAPÍTULO 8 Construindo o thinFormation 109

CAPÍTULO 8

Construindo o thinFormation

Introdução Neste estão informações para que o desenvolvedor possa construir um


programa baseado no template thinFormation.
A seguir está um exemplo de um programa construído com o template
thinFormation:
110

Vale ressaltar que toda a exemplificação será feita utilizando o banco de dados
Sports.

Características As características deste são:


 algumas das funções são realizadas na própria tela base do programa;
 faz uso do sistema de tradução de .R, bastando para tanto identificar as
strings que não devem ser traduzidas com :U (Exemplo: "CHOOSE":U).
Observação: O identificador :T no início de alguns comentários, é usado para a
tradução dos fontes dos templates para outros idiomas. Este identificador não
afeta em nada a funcionalidade do programa.

Tarefas
A seguir é apresentada a lista de tarefas para desenvolvimento do programa.

Preprocessors Inicialmente devem ser definidos os valores dos preprocessors padrão do


programa.
Preprocessor Descrição
Program Nome do programa – Formato (XX9999)
Version Versão do programa – Formato (9.99.99.999)
First O valor YES indica que o programa possui a função de
posicionamento no primeiro registro
Prev O valor YES indica que o programa possui a função de
posicionamento no registro anterior
Next O valor YES indica que o programa possui a função de
posicionamento no próximo registro
Last O valor YES indica que o programa possui a função de
posicionamento no último registro
GoTo O valor YES indica que o programa possui a função de
Vá Para
Search O valor YES indica que o programa possui a função de
Pesquisa
AddTarget O valor YES indica que o programa possui a função de
incluir na tabela formação
AddAllTarget O valor YES indica que o programa possui a função de
incluir todos na tabela formação
CAPÍTULO 8 Construindo o thinFormation 111

Preprocessor Descrição
DelTarget O valor YES indica que o programa possui a função de
retirar na tabela formação
DelAllTarget O valor YES indica que o programa possui a função de
retirar todos na tabela formação
UpdateTarget O valor YES indica que o programa possui a função de
alteração na tabela formação
ttParent Nome da temp-table pai utilizada para comunicação com
o DBO
HDBOParent Nome da variável que contém o handle do DBO pai
DBOParentTable Nome da tabela principal do DBO pai
ttSource Nome da temp-table origem utilizada para cominicação
com o DBO
HDBOSource Nome da variável que contém o handle do DBO origem
DBOSourceTable Nome da tabela principal do DBO origem
ttTarget Nome da temp-table destino (formação) utilizada para
comunicação com o DBO
HDBOTarget Nome da variável que contém o handle do DBO destino
DBOTargetTable Nome da tabela principal do DBO destino
Page0Fields Nome dos campos da temp-table pai (principal) que
estão na frame fPage0
SourceBrowse Nome do browser Origem
TargetBrowse Nome do browser Destino (formação)

Observação O preprocessor Program refere-se ao nome com o qual o programa


está ou será cadastrado no menu.
Exemplo de código com o preenchimento dos preprocessadores:
&GLOBAL-DEFINE Program thinFormation
&GLOBAL-DEFINE Version 1.00.00.000

&GLOBAL-DEFINE First YES


&GLOBAL-DEFINE Prev YES
&GLOBAL-DEFINE Next YES
&GLOBAL-DEFINE Last YES
&GLOBAL-DEFINE GoTo YES
&GLOBAL-DEFINE Search YES

&GLOBAL-DEFINE UpdateTarget YES

&GLOBAL-DEFINE DelTarget YES


&GLOBAL-DEFINE AddTarget YES
&GLOBAL-DEFINE DelAllTarget YES
112

&GLOBAL-DEFINE AddAllTarget YES

&GLOBAL-DEFINE ttParent ttOrder


&GLOBAL-DEFINE hDBOParent hDBOOrder
&GLOBAL-DEFINE DBOParentTable Order

&GLOBAL-DEFINE ttTarget ttOrder-Line


&GLOBAL-DEFINE hDBOTarget hDBOOrder-Line
&GLOBAL-DEFINE DBOTargetTable Order-Line

&GLOBAL-DEFINE ttSource ttItem


&GLOBAL-DEFINE hDBOSource hDBOItem
&GLOBAL-DEFINE DBOSourceTable Item

&GLOBAL-DEFINE page0Fields ttOrder.Order-Num ~


ttOrder.Order-Date ~
ttOrder.Sales-Rep
&GLOBAL-DEFINE sourceBrowse brSource
&GLOBAL-DEFINE targetBrowse brTarget

Quando o desenvolvedor optar por retirar uma ou mais funções do programa,


deve-se alterar o conteúdo do preprocessor correspondente e, além disso,
eliminar os botões, menus etc, relacionados à função eliminada.
Para retirar os botões de Consultas Relacionadas e Relatórios Relacionados, o
desenvolvedor deve incluir o preprocessor padrão referente ao botão que
deseja retirar.
&GLOBAL-DEFINE ExcludeBtQueryJoins YES
&GLOBAL-DEFINE ExcludeBtReportsJoins YES

Para definir o número de registros que devem ser retornados para o browse,
deve-se utilizar os preprocessors padrão descritos anteriormente e acrescentar
o preprocessor padrão a seguir:
Preprocessor Descrição
NumRowsReturnedSource Número de registros que devem ser retornados
no browse
NumRowsReturnedTarget Número de registros que devem ser retornados
no browse

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se criar um
preprocessador chamado DBOVersion, na sessão Definitions, com o valor
1.1. A seguir modelo de sua definição:
&GLOBAL-DEFINE DBOVersion 1.1
CAPÍTULO 8 Construindo o thinFormation 113

Temp-Table de Criar as temp-tables que são utilizadas para realizar a comunicação com os
Comunicação DBOs. E devem estar disponíveis para inclusão de campos em tela.
Para tanto deve-se utilizar o menu Tools | Procedure Settings, botão:

A tela a seguir é aberta, nesta devem criar-se as temp-tables e definir um


campo chamado r-Rowid. E ainda, as definições destas temp-tables devem
ser idênticas as definições das temp-tables dos DBOs.

Queries para os As queries dos browsers devem ser geradas com um FOR EACH simples na
browses TEMP-TABLE de comunicação da interface.
114

Instâncias do As criações das instâncias do DBOs (DBO Pai, DBO Origem e DBO Destino)
DBOs devem ser feitas manualmente, utilizando ou não o recurso de RPC. Logo após
deve-se definir as restrições iniciais e a abertura da query do DBO Pai, caso
necessário.
As instâncias dos DBOs são feitas no método initializeDBOs.
A seguir existe uma tabela que possui o nome dos parâmetros e suas
descrições:
Parâmetro Descrição
DBOParentProgram Nome físico do programa DBO pai (principal)
Description Identifica o nome da constraint a ser utilizada
inicialmente para o DBO pai (principal)
Query Identifica o nome da query a ser utilizada para realizar
a abertura inicial do DBO pai
CAPÍTULO 8 Construindo o thinFormation 115

Parâmetro Descrição
DBOSourceProgram Nome físico do programa DBO origem
DBOTargetProgram Nome físico do programa DBO destino (formação)

Exemplo de código com o preenchimento dos parâmetros:


/*------------------------------------------------------------------
Purpose: Inicializa DBOs
Parameters:
Notes:
------------------------------------------------------------------*/

/*--- Verifica se o DBO da tabela Pai já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOParent}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOOrder.p}
{btb/btb008za.i2 C:/Programs/DBOOrder.p '' {&hDBOParent}}
END.

RUN openQueryStatic IN {&hDBOParent} (INPUT "OrderNum":U).

/*--- Verifica se o DBO da tabela Origem já está inicializado ---*/

IF NOT VALID-HANDLE({&hDBOSource}) THEN DO:


{btb/btb008za.i1 C:/Programs/DBOItem.p }
{btb/btb008za.i2 C:/Programs/DBOItem.p '' {&hDBOSource}}
END.

/*---Verifica se o DBO da tabela Formação já está inicializado ---*/

IF NOT VALID-HANDLE({&hDBOTarget}) THEN DO:


{btb/btb008za.i1 C:/Programs/DBOOrder-Line.p }
{btb/btb008za.i2 C:/Programs/DBOOrder-Line.p '' {&hDBOTarget}}
END.

RETURN "OK":U.

END PROCEDURE.

A associação entre o DBO Pai e os DBOs Filho é vista posteriormente.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
métodos disponíveis nesta versão. Além disso, o desenvolvedor deve usar o
preprocessador DBOVersion a fim de permitir fácil migração do programa
para o DBO 2.0.
A seguir modelo de instância de BO 1.1, preparado para migração:
PROCEDURE initializeDBOs:
116

/*-----------------------------------------------------------------
Purpose: Inicializa DBOs
Parameters:
Notes:
-----------------------------------------------------------------*/

/*--- Verifica se o DBO da tabela Pai já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOParent}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOOrder.p}
{btb/btb008za.i2 C:/Programs/DBOOrder.p '' {&hDBOParent}}
END.

/*--- Abre query CustNum ou 1 do DBO ---*/


&IF DEFINED(DBOVersion) <> 0 &THEN
RUN openQuery IN {&hDBOParent} (INPUT 1).
&ELSE
RUN openQueryStatic IN {&hDBOParent} (INPUT "OrderNum":U).
&ENDIF

/*--- Verifica se o DBO da tabela Origem já está inicializado ---*/

IF NOT VALID-HANDLE({&hDBOSource}) THEN DO:


{btb/btb008za.i1 C:/Programs/DBOItem.p }
{btb/btb008za.i2 C:/Programs/DBOItem.p '' {&hDBOSource}}
END.

/*---Verifica se o DBO da tabela Formação já está inicializado ---*/

IF NOT VALID-HANDLE({&hDBOTarget}) THEN DO:


{btb/btb008za.i1 C:/Programs/DBOOrder-Line.p }
{btb/btb008za.i2 C:/Programs/DBOOrder-Line.p '' {&hDBOTarget}}
END.

RETURN "OK":U.
END PROCEDURE.

Widgets de Para inclusão dos widgets da temp-table de comunicação, que apresentam os


Comunicação valores do DBO Pai, deve-se utilizar o botão a seguir:

A tela a seguir é aberta, nesta deve selecionar-se o item Temp-Tables, a temp-


table desejada e logo após os campos a serem inclusos na frame de trabalho:
CAPÍTULO 8 Construindo o thinFormation 117

Após a inclusão dos campos, ou widgets comuns, devem ser feitas algumas
alterações de suas propriedades. Estas são descritas a seguir:
 devem estar dispostos em linha, e caso necessário em colunas;
 para widgets do tipo fill-in, sua altura deve ser de 0.88;
 para widgets dos tipos combo-box, suas alturas devem ser de 1.00;
 para widgets dos tipos editores ou list-box ou radio-set, suas alturas devem
ser definidas pelo próprio desenvolvedor;
 para os widgets que fazem parte da temp-table Pai, devem ser dispostos no
retângulo rtParent;
Observação Para os campos do tipo fill-in’s, deve ser observado se o mesmo possue trigger
de "LEAVE"/"VALUE-CHANGED" e não tenha lupa como cursor do mouse ou um botão de
zoom na sua direita; ou possua trigger de "ENTRY". Caso o fill-in se encaixe em uma das
opções acima, deve ser efetuado o registro para o WebEnabler, conforme técnica Como registrar
campo do tipo Fill-in para o WebEnabler do Manual de Padrões.
O WebEnabler já registra automaticamente o evento de "LEAVE" para TODOS os fill-ins que
possuírem a lupa como cursor do mouse, ou que possuírem um botão de zoom na sua direita.
Portanto não é necessário efetuar o registro para esses fill-ins.

Método O método openQueries é responsável por realizar a ligação entre o DBO Pai
openQueries e o DBO destino (formação) e abrir a query do DBO Origem. Para tanto é feito
o uso dos includes formation/OpenQueriesTarget.i para atualizar os
dados do browser Destino e formation/OpenQueriesSource.i para
atualizar os dados do browser Origem.
118

Uma das características destes includes é a de trazer somente os 40 (quarenta)


primeiros registros associados aos browsers. Os próximos registros são
trazidos quando ocorrem os eventos de Cursor-Down, End, Off-End e
Page-Down, utilizando o mesmo método.
A seguir existe uma tabela que possui o nome dos parâmetros e suas
descrições:
formation/openQueriesTarget.i
Parâmetro Descrição
Parent Nome da tabela pai, utilizado para designar o método
linkTo<Parent>
Query Identifica o nome da query a ser utilizada para
realizar a abertura do DBO Destino

formation/openQueriesSource.i
Parâmetro Descrição
Query Identifica o nome da query a ser utilizada para
realizar a abertura do DBO Origem
ConstraintParameters Parâmetros a serem utilizados para o método
setConstraint{&Description}
OpenAlways O valor YES indica que o browse Origem deve ser
atualizado a cada vez que for efetuada navegação na
tabela Pai

/*----------------------------------------------------------------------
Purpose: Atualiza browsers
Parameters:
Notes:
----------------------------------------------------------------------*/

{Formation/OpenQueriesTarget.i &Parent="Order"
&Query="Order-Num"}

{Formation/OpenQueriesSource.i &Query="Item-Num"
&OpenAlways="no"}

RETURN "OK":U.
END PROCEDURE.
CAPÍTULO 8 Construindo o thinFormation 119

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
novos parâmetros para os includes formation/OpenQueriesTarget.i e
formation/OpenQueriesSource.i. A seguir existe uma tabela que possui
o nome dos novos parâmetros e suas descrições:
formation/openQueriesTarget.i
Parâmetro Descrição
QueryConstraint Número que identifica a query e constraint, a ser
utilizado para passagem de parâmetro para o método
openQuery e para a definição do método
setConstraint{&QueryConstraint}
ConstraintParameters Parâmetros a serem utilizados para o método
setContraint{&QueryConstraint}

formation/openQueriesSource.i
Parâmetro Descrição
QueryConstraint Número que identifica a query e constraint, a ser
utilizado para passagem de parâmetro para o método
openQuery e para a definição do método
setConstraint{&QueryConstraint}
ConstraintParameters Parâmetros a serem utilizados para o método
setContraint{&QueryConstraint}
OpenAlways O valor YES indica que o browse Origem deve ser
atualizado a cada vez que for efetuada navegação na
tabela Pai

Exemplo de código com o preenchimento dos novos parâmetros:


/*----------------------------------------------------------------------
Purpose: Atualiza browsers
Parameters:
Notes:
----------------------------------------------------------------------*/

{Formation/OpenQueriesTarget.i &QueryConstraint="1"
&ConstraintParameters=ttOrder.Order-Num}

{Formation/OpenQueriesSource.i &QueryConstraint="1"
&OpenAlways="no"}

RETURN "OK":U.
END PROCEDURE.
120

Save O método saveParentFields é responsável por atualizar a tabela de


Parent Fields formação com base nos campos da tabela pai e tabela origem.
Exemplo de código a ser implementado no método saveParentFields:

/*-----------------------------------------------------------------
Purpose: Salva valores dos campos da tabela formação ({&ttTarget})
com base nos campos da tabela pai ({&ttParent}) e tabela
origem ({&ttSource})
Parameters:
-----------------------------------------------------------------*/
assign {&ttTarget}.order-num = {&ttParent}.order-num
{&ttTarget}.item-num = {&ttSource}.item-num
{&ttTarget}.qty = 1
{&ttTarget}.Price = {&ttSource}.price.

RETURN "OK":U.
END PROCEDURE.

Triggers de botões Para os botões padrão existem métodos ou includes padrão que precisam ser
padrão definidos.
Inicialmente todos os botões já estão com valores prefixados, somente
necessitanto serem alterados em alguns casos.
A seguir existe uma tabela que possui a identificação das triggers, dos
parâmetros e suas descrições:
 Trigger de Choose para o botão btUpdateTarget :
Parâmetro Descrição
ProgramTarget Nome do programa a ser executado para realizar a
alteração de registro da tabela formação

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btUdpateTarget IN FRAME fPage1 DO:
{masterdetail/UpdateTarget.i
&ProgramTarget="C:/Programs/MaintenanceNoNavigationOrder.w"}
END.
CAPÍTULO 8 Construindo o thinFormation 121

 Trigger de Choose para o botão btSearch :


Parâmetro Descrição
ProgramZoom Nome do programa a ser executado para realizar a
pesquisa de registros

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btSearch IN FRAME fPage0 /* Search */
OR CHOOSE OF MENU-ITEM miSearch IN MENU mbMain DO:
{method/ZoomReposition.i &ProgramZoom="C:/Programs/Zoom.w "}
END.

Método O método goToRecord é responsável pela função de Vá Para da tabela pai,


goToRecord disparada pelo botão btGoTo e pelo menu miGoTo.
O código do método está predefinido, mas necessita de pequenas alterações.
Tais como a definição dos campos a serem utilizados, tamanho da frame etc.
A seguir existe uma tabela que possui o nome dos parâmetros e suas
descrições:
Parâmetro Descrição
<c|d|i> Indica o tipo de variável (c = character, d = decimal, i =
integer)
<campo N> nomes dos campos a serem inclusos na frame de Vá
Para
<Tabela> nome da tabela a ser utilizado para definir o título da
frame de Vá Para

Exemplo de código com o preenchimento dos parâmetros:


PROCEDURE goToRecord:
/*---------------------------------------------------------------------
Purpose: Exibe dialog de Vá Para
Parameters:
Notes:
---------------------------------------------------------------------*/
DEFINE BUTTON btGoToCancel AUTO-END-KEY
LABEL "&Cancelar"
SIZE 10 BY 1
BGCOLOR 8.
DEFINE BUTTON btGoToOK AUTO-GO
LABEL "&OK"
SIZE 10 BY 1
122

BGCOLOR 8.
DEFINE RECTANGLE rtGoToButton
EDGE-PIXELS 2 GRAPHIC-EDGE
SIZE 35 BY 1.42
BGCOLOR 7.
DEFINE VARIABLE rGoTo AS ROWID NO-UNDO.
DEFINE VARIABLE iOrder-Num LIKE ttOrder.Order-Num NO-UNDO.
DEFINE FRAME fGoToRecord
iOrder-Num AT ROW 1.21 COL 15 COLON-ALIGNED
btGoToOK AT ROW 2.63 COL 2.14
btGoToCancel AT ROW 2.63 COL 13
rtGoToButton AT ROW 2.38 COL 1
SPACE(0.28)
WITH VIEW-AS DIALOG-BOX KEEP-TAB-ORDER SIDE-LABELS NO-UNDERLINE
THREE-D SCROLLABLE FONT 1 TITLE "Vá Para Order"
DEFAULT-BUTTON btGoToOK CANCEL-BUTTON btGoToCancel.

RUN utp/ut-trfrrp.p (input Frame fGoToRecord:Handle).


{utp/ut-liter.i "Vá_Para_<tabela>"}
ASSIGN FRAME fGoToRecord:TITLE = RETURN-VALUE.
ON "CHOOSE":U OF btGoToOK IN FRAME fGoToRecord DO:
ASSIGN iOrderNum.
RUN goToKey IN {&hDBOTable} (INPUT iOrderNum).
IF RETURN-VALUE = "NOK":U THEN DO:
RUN utp/ut-msgs.p (INPUT "SHOW":U, INPUT 2, INPUT "Order":U).

RETURN NO-APPLY.
END.

/* Retorna rowid do registro corrente do DBO */


RUN getRowid IN {&hDBOTable} (OUTPUT rGoTo).

/* Reposiciona registro com base em um rowid */


RUN repositionRecord IN THIS-PROCEDURE (INPUT rGoTo).

APPLY "GO":U TO FRAME fGoToRecord.


END.

ENABLE iOrder-Num btGoToOK btGoToCancel


WITH FRAME fGoToRecord.

WAIT-FOR "GO":U OF FRAME fGoToRecord.


END PROCEDURE.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
métodos disponíveis nesta versão. Além disso, o desenvolvedor deve usar o
preprocessador DBOVersion a fim de permitir fácil migração do programa
para o DBO 2.0.
CAPÍTULO 8 Construindo o thinFormation 123

A seguir modelo do método goToRecord, preparado para migração:


PROCEDURE goToRecord:
/*---------------------------------------------------------------------
Purpose: Exibe dialog de Vá Para
Parameters:
Notes:
---------------------------------------------------------------------*/

DEFINE BUTTON btGoToCancel AUTO-END-KEY


LABEL "&Cancelar"
SIZE 10 BY 1
BGCOLOR 8.

DEFINE BUTTON btGoToOK AUTO-GO


LABEL "&OK"
SIZE 10 BY 1
BGCOLOR 8.

DEFINE RECTANGLE rtGoToButton


EDGE-PIXELS 2 GRAPHIC-EDGE
SIZE 35 BY 1.42
BGCOLOR 7.

DEFINE VARIABLE cStatus AS CHARACTER NO-UNDO.

DEFINE VARIABLE rGoTo AS ROWID NO-UNDO.

DEFINE VARIABLE iOrder-Num LIKE ttOrder.Order-Num NO-UNDO.

DEFINE FRAME fGoToRecord


iOrder-Num AT ROW 1.21 COL 15 COLON-ALIGNED
btGoToOK AT ROW 2.63 COL 2.14
btGoToCancel AT ROW 2.63 COL 13
rtGoToButton AT ROW 2.38 COL 1
SPACE(0.28)
WITH VIEW-AS DIALOG-BOX KEEP-TAB-ORDER SIDE-LABELS NO-UNDERLINE
THREE-D SCROLLABLE FONT 1 TITLE "Vá Para Order"
DEFAULT-BUTTON btGoToOK CANCEL-BUTTON btGoToCancel.

RUN utp/ut-trfrrp.p (input Frame fGoToRecord:Handle).


{utp/ut-liter.i "Vá_Para_<tabela>"}
ASSIGN FRAME fGoToRecord:TITLE = RETURN-VALUE.

ON "CHOOSE":U OF btGoToOK IN FRAME fGoToRecord DO:


ASSIGN iCustNum.

&IF DEFINED(DBOVersion) <> 0 &THEN


RUN findOrder-Num IN {&hDBOTable} (INPUT iOrderNum,
OUTPUT cStatus).
IF cStatus <> "":U THEN DO:
RUN utp/ut-msgs.p (INPUT "SHOW":U,
INPUT 2,
INPUT "Order":U).

RETURN NO-APPLY.
124

END.
&ELSE
RUN goToKey IN {&hDBOTable} (INPUT iOrderNum).
IF RETURN-VALUE = "NOK":U THEN DO:
RUN utp/ut-msgs.p (INPUT "SHOW":U,
INPUT 2,
INPUT "Order":U).

RETURN NO-APPLY.
END.
&ENDIF

/* Retorna rowid do registro corrente do DBO */


RUN getRowid IN {&hDBOTable} (OUTPUT rGoTo).

/* Reposiciona registro com base em um rowid */


RUN repositionRecord IN THIS-PROCEDURE (INPUT rGoTo).

APPLY "GO":U TO FRAME fGoToRecord.


END.

ENABLE iOrder-Num btGoToOK btGoToCancel


WITH FRAME fGoToRecord.

WAIT-FOR "GO":U OF FRAME fGoToRecord.


END PROCEDURE.

Considerações
Quando é construído um programa utilizando o template thinFormation
necessita-se realizar a implementação de lógicas auxiliares, tais como:
 programa de pesquisa de chave estrangeira;
 referência para campos de chave estrangeira.
Para tanto, deve-se utilizar o capítulo de Técnicas.

Além disso, necessita-se realizar a construção separadamente, em muitas


situações, dos programas a seguir:
 programa de pesquisa de pai;
CAPÍTULO 8 Construindo o thinFormation 125

 programa de manutenção da tabela formação.


Para a construção destes programas devem ser utilizados capítulos separados,
tais como:
 Construindo o thinZoom;
 Construindo o thinMaintenanceNoNavigation
126

CAPÍTULO 9

Construindo o thinFormationNoNavigation

Introdução Neste estão informações para que o desenvolvedor possa construir um


programa baseado no template thinFormationNoNavigation.
A seguir está um exemplo de um programa construído com o template

thinFormationNoNavigation:
CAPÍTULO 9 Construindo o thinFormationNoNavigation 127

Vale ressaltar que toda a exemplificação será feita utilizando o banco de dados
Sports.

Características As características deste são:


 algumas das funções são realizadas na própria tela base do programa;
 faz uso do sistema de tradução de .R, bastando para tanto identificar as
strings que não devem ser traduzidas com :U (Exemplo: "CHOOSE":U).
Observação: O identificador :T no início de alguns comentários, é usado para a
tradução dos fontes dos templates para outros idiomas. Este identificador não
afeta em nada a funcionalidade do programa.

Tarefas
A seguir é apresentada a lista de tarefas para desenvolvimento do programa.

Preprocessors Inicialmente devem ser definidos os valores dos preprocessors padrão do


programa.
Preprocessor Descrição
Program Nome do programa – Formato (XX9999)
Version Versão do programa – Formato (9.99.99.999)
AddTarget O valor YES indica que o programa possui a função de
incluir na tabela formação
AddAllTarget O valor YES indica que o programa possui a função de
incluir todos na tabela formação
DelTarget O valor YES indica que o programa possui a função de
retirar na tabela formação
DelAllTarget O valor YES indica que o programa possui a função de
retirar todos na tabela formação
UpdateTarget O valor YES indica que o programa possui a função de
alteração na tabela formação
ttParent Nome da temp-table pai utilizada para comunicação com
o DBO
HDBOParent Nome da variável que contém o handle do DBO pai
DBOParentTable Nome da tabela principal do DBO pai
ttSource Nome da temp-table origem utilizada para cominicação
128

Preprocessor Descrição
com o DBO
HDBOSource Nome da variável que contém o handle do DBO origem
DBOSourceTable Nome da tabela principal do DBO origem
ttTarget Nome da temp-table destino (formação) utilizada para
comunicação com o DBO
HDBOTarget Nome da variável que contém o handle do DBO destino
DBOTargetTable Nome da tabela principal do DBO destino
Page0Fields Nome dos campos da temp-table pai (principal) que
estão na frame fPage0
SourceBrowse Nome do browser Origem
TargetBrowse Nome do browser Destino (formação)

Observação O preprocessor Program refere-se ao nome com o qual o programa


está ou será cadastrado no menu.
Exemplo de código com o preenchimento dos preprocessadores:
&GLOBAL-DEFINE Program thinFormationNoNavigation
&GLOBAL-DEFINE Version 1.00.00.000

&GLOBAL-DEFINE DelTarget YES


&GLOBAL-DEFINE AddTarget YES
&GLOBAL-DEFINE DelAllTarget YES
&GLOBAL-DEFINE AddAllTarget YES

&GLOBAL-DEFINE UpdateTarget YES

&GLOBAL-DEFINE ttParent ttOrder


&GLOBAL-DEFINE hDBOParent hDBOOrder
&GLOBAL-DEFINE DBOParentTable Order

&GLOBAL-DEFINE ttTarget ttOrder-Line


&GLOBAL-DEFINE hDBOTarget hDBOOrder-Line
&GLOBAL-DEFINE DBOTargetTable Order-Line

&GLOBAL-DEFINE ttSource ttItem


&GLOBAL-DEFINE hDBOSource hDBOItem
&GLOBAL-DEFINE DBOSourceTable Item

&GLOBAL-DEFINE page0Fields ttOrder.Order-Num ~


ttOrder.Order-Date ~
ttOrder.Sales-Rep
&GLOBAL-DEFINE sourceBrowse brSource
&GLOBAL-DEFINE targetBrowse brTarget
CAPÍTULO 9 Construindo o thinFormationNoNavigation 129

Quando o desenvolvedor optar por retirar uma ou mais funções do programa,


deve-se alterar o conteúdo do preprocessor correspondente e, além disso,
eliminar os botões, menus etc, relacionados à função eliminada.
Para definir o número de registros que devem ser retornados para o browse,
deve-se utilizar os preprocessors padrão descritos anteriormente e acrescentar
o preprocessor padrão a seguir:
Preprocessor Descrição
NumRowsReturnedSource Número de registros que devem ser retornados
no browse
NumRowsReturnedTarget Número de registros que devem ser retornados
no browse

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se criar um
preprocessador chamado DBOVersion, na sessão Definitions, com o valor
1.1. A seguir modelo de sua definição:
&GLOBAL-DEFINE DBOVersion 1.1

Temp-Table de Criar as temp-tables que são utilizadas para realizar a comunicação com os
Comunicação DBOs. E devem estar disponíveis para inclusão de campos em tela.
Para tanto deve-se utilizar o menu Tools | Procedure Settings, botão:

A tela a seguir é aberta, nesta devem criar-se as temp-tables e definir um


campo chamado r-Rowid. E ainda, as definições destas temp-tables devem
ser idênticas as definições das temp-tables dos DBOs.
130

Instâncias do As criações das instâncias do DBOs (DBO Pai, DBO Origem e DBO Destino)
DBOs devem ser feitas manualmente, utilizando ou não o recurso de RPC. Logo após
deve-se definir as restrições iniciais e a abertura da query do DBO Pai, caso
necessário.
As instâncias dos DBOs são feitas no método initializeDBOs.
A seguir existe uma tabela que possui o nome dos parâmetros e suas
descrições:
Parâmetro Descrição
DBOParentProgram Nome físico do programa DBO pai (principal)
Description Identifica o nome da constraint a ser utilizada
inicialmente para o DBO pai (principal)
Query Identifica o nome da query a ser utilizada para realizar
a abertura inicial do DBO pai
CAPÍTULO 9 Construindo o thinFormationNoNavigation 131

Parâmetro Descrição
DBOSourceProgram Nome físico do programa DBO origem
DBOTargetProgram Nome físico do programa DBO destino (formação)

Exemplo de código com o preenchimento dos parâmetros:


/*------------------------------------------------------------------
Purpose: Inicializa DBOs
Parameters:
Notes:
------------------------------------------------------------------*/

/*--- Verifica se o DBO da tabela Pai já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOParent}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOOrder.p}
{btb/btb008za.i2 C:/Programs/DBOOrder.p '' {&hDBOParent}}
END.

RUN openQueryStatic IN {&hDBOParent} (INPUT "OrderNum":U).

/*--- Verifica se o DBO da tabela Origem já está inicializado ---*/

IF NOT VALID-HANDLE({&hDBOSource}) THEN DO:


{btb/btb008za.i1 C:/Programs/DBOItem.p }
{btb/btb008za.i2 C:/Programs/DBOItem.p '' {&hDBOSource}}
END.

/*---Verifica se o DBO da tabela Formação já está inicializado ---*/

IF NOT VALID-HANDLE({&hDBOTarget}) THEN DO:


{btb/btb008za.i1 C:/Programs/DBOOrder-Line.p }
{btb/btb008za.i2 C:/Programs/DBOOrder-Line.p '' {&hDBOTarget}}
END.

RETURN "OK":U.

END PROCEDURE.

A associação entre o DBO Pai e os DBOs Filho é vista posteriormente.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
métodos disponíveis nesta versão. Além disso, o desenvolvedor deve usar o
preprocessador DBOVersion a fim de permitir fácil migração do programa
para o DBO 2.0.
A seguir modelo de instância de BO 1.1, preparado para migração:
PROCEDURE initializeDBOs:
132

/*-----------------------------------------------------------------
Purpose: Inicializa DBOs
Parameters:
Notes:
-----------------------------------------------------------------*/

/*--- Verifica se o DBO da tabela Pai já está inicializado ---*/


IF NOT VALID-HANDLE({&hDBOParent}) THEN DO:
{btb/btb008za.i1 C:/Programs/DBOOrder.p}
{btb/btb008za.i2 C:/Programs/DBOOrder.p '' {&hDBOParent}}
END.

/*--- Abre query CustNum ou 1 do DBO ---*/


&IF DEFINED(DBOVersion) <> 0 &THEN
RUN openQuery IN {&hDBOParent} (INPUT 1).
&ELSE
RUN openQueryStatic IN {&hDBOParent} (INPUT "OrderNum":U).
&ENDIF

/*--- Verifica se o DBO da tabela Origem já está inicializado ---*/

IF NOT VALID-HANDLE({&hDBOSource}) THEN DO:


{btb/btb008za.i1 C:/Programs/DBOItem.p }
{btb/btb008za.i2 C:/Programs/DBOItem.p '' {&hDBOSource}}
END.

/*---Verifica se o DBO da tabela Formação já está inicializado ---*/

IF NOT VALID-HANDLE({&hDBOTarget}) THEN DO:


{btb/btb008za.i1 C:/Programs/DBOOrder-Line.p }
{btb/btb008za.i2 C:/Programs/DBOOrder-Line.p '' {&hDBOTarget}}
END.

RETURN "OK":U.
END PROCEDURE.

Widgets de Para inclusão dos widgets da temp-table de comunicação, que apresentam os


Comunicação valores do DBO Pai, deve-se utilizar o botão a seguir:

A tela a seguir é aberta, nesta deve selecionar-se o item Temp-Tables, a temp-


table desejada e logo após os campos a serem inclusos na frame de trabalho:
CAPÍTULO 9 Construindo o thinFormationNoNavigation 133

Após a inclusão dos campos, ou widgets comuns, devem ser feitas algumas
alterações de suas propriedades. Estas são descritas a seguir:
 devem estar dispostos em linha, e caso necessário em colunas;
 para widgets do tipo fill-in, sua altura deve ser de 0.88;
 para widgets dos tipos combo-box, suas alturas devem ser de 1.00;
 para widgets dos tipos editores ou list-box ou radio-set, suas alturas devem
ser definidas pelo próprio desenvolvedor;
 para os widgets que fazem parte da temp-table Pai, devem ser dispostos no
retângulo rtParent;
Observação Para os campos do tipo fill-in’s, deve ser observado se o mesmo possue trigger
de "LEAVE"/"VALUE-CHANGED" e não tenha lupa como cursor do mouse ou um botão de
zoom na sua direita; ou possua trigger de "ENTRY". Caso o fill-in se encaixe em uma das
opções acima, deve ser efetuado o registro para o WebEnabler, conforme técnica Como registrar
campo do tipo Fill-in para o WebEnabler do Manual de Padrões.
O WebEnabler já registra automaticamente o evento de "LEAVE" para TODOS os fill-ins que
possuírem a lupa como cursor do mouse, ou que possuírem um botão de zoom na sua direita.
Portanto não é necessário efetuar o registro para esses fill-ins.

Método O método openQueries é responsável por realizar a ligação entre o DBO Pai
openQueries e o DBO destino (formação) e abrir a query do DBO Origem. Para tanto é feito
o uso dos includes formationNoNavigation/OpenQueriesTarget.i
para atualizar os dados do browser Destino e
formationNoNavigation/OpenQueriesSource.i para atualizar os
dados do browser Origem.
134

Uma das características destes includes é a de trazer somente os 40 (quarenta)


primeiros registros associados aos browsers. Os próximos registros são
trazidos quando ocorrem os eventos de Cursor-Down, End, Off-End e
Page-Down, utilizando o mesmo método.

A seguir existe uma tabela que possui o nome dos parâmetros e suas
descrições:
formationNoNavigation/openQueriesTarget.i
Parâmetro Descrição
Parent Nome da tabela pai, utilizado para designar o método
linkTo<Parent>
Query Identifica o nome da query a ser utilizada para
realizar a abertura do DBO Destino

formationNoNavigation/openQueriesSource.i
Parâmetro Descrição
Query Identifica o nome da query a ser utilizada para
realizar a abertura do DBO Origem
ConstraintParameters Parâmetros a serem utilizados para o método
setConstraint{&Description}
OpenAlways O valor YES indica que o browse Origem deve ser
atualizado a cada vez que for efetuada navegação na
tabela Pai

/*----------------------------------------------------------------------
Purpose: Atualiza browsers
Parameters:
Notes:
----------------------------------------------------------------------*/

{FormationNoNavigation/OpenQueriesTarget.i &Parent="Order"
&Query="Order-Num"}

{FormationNoNavigation/OpenQueriesSource.i &Query="Item-Num"
&OpenAlways="no"}
CAPÍTULO 9 Construindo o thinFormationNoNavigation 135

RETURN "OK":U.
END PROCEDURE.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
novos parâmetros para os includes formation/OpenQueriesTarget.i e
formation/OpenQueriesSource.i. A seguir existe uma tabela que possui
o nome dos novos parâmetros e suas descrições:
formationNoNavigation/openQueriesTarget.i
Parâmetro Descrição
QueryConstraint Número que identifica a query e constraint, a ser
utilizado para passagem de parâmetro para o método
openQuery e para a definição do método
setConstraint{&QueryConstraint}
ConstraintParameters Parâmetros a serem utilizados para o método
setContraint{&QueryConstraint}

formationNoNavigation/openQueriesSource.i
Parâmetro Descrição
QueryConstraint Número que identifica a query e constraint, a ser
utilizado para passagem de parâmetro para o método
openQuery e para a definição do método
setConstraint{&QueryConstraint}
ConstraintParameters Parâmetros a serem utilizados para o método
setContraint{&QueryConstraint}
OpenAlways O valor YES indica que o browse Origem deve ser
atualizado a cada vez que for efetuada navegação na
tabela Pai

Exemplo de código com o preenchimento dos novos parâmetros:


/*----------------------------------------------------------------------
Purpose: Atualiza browsers
Parameters:
Notes:
----------------------------------------------------------------------*/

{Formation/OpenQueriesTarget.i &QueryConstraint="1"
&ConstraintParameters=ttOrder.Order-Num}

{Formation/OpenQueriesSource.i &QueryConstraint="1"
136

&OpenAlways="no"}

RETURN "OK":U.
END PROCEDURE.

Save O método saveParentFields é responsável por atualizar a tabela de


Parent Fields formação com base nos campos da tabela pai e tabela origem.
Exemplo de código a ser implementado no método saveParentFields:

/*-----------------------------------------------------------------
Purpose: Salva valores dos campos da tabela formação ({&ttTarget})
com base nos campos da tabela pai ({&ttParent}) e tabela
origem ({&ttSource})
Parameters:
-----------------------------------------------------------------*/
assign {&ttTarget}.order-num = {&ttParent}.order-num
{&ttTarget}.item-num = {&ttSource}.item-num
{&ttTarget}.qty = 1
{&ttTarget}.Price = {&ttSource}.price.

RETURN "OK":U.
END PROCEDURE.

Triggers de bot ões Para os botões padrão existem métodos ou includes padrão que precisam ser
padrão definidos.
Inicialmente todos os botões já estão com valores prefixados, somente
necessitanto serem alterados em alguns casos.
A seguir existe uma tabela que possui a identificação das triggers, dos
parâmetros e suas descrições:
 Trigger de Choose para o botão btUpdateTarget :
Parâmetro Descrição
ProgramTarget Nome do programa a ser executado para realizar a
alteração de registro da tabela formação

Exemplo de código com o preenchimento dos parâmetros:


ON CHOOSE OF btUdpateTarget IN FRAME fPage1 DO:
{masterdetail/UpdateTarget.i
&ProgramTarget="C:/Programs/MaintenanceNoNavigationOrder.w"}
CAPÍTULO 9 Construindo o thinFormationNoNavigation 137

END.

Considerações
Quando é construído um programa utilizando o template
thinFormationNoNaviagation necessita-se realizar a implementação de lógicas
auxiliares, tais como:
 programa de pesquisa de chave estrangeira;
 referência para campos de chave estrangeira.
Para tanto, deve-se utilizar o capítulo de Técnicas.

Além disso, necessita-se realizar a construção separadamente, em muitas


situações, dos programas a seguir:
 programa de manutenção da tabela formação.
Para a construção deste programa deve ser utilizado o capítulo:
 Construindo o thinMaintenanceNoNavigation
139

CAPÍTULO 10

Técnicas

Introdução Neste estão informações para que o desenvolvedor possa implementar novas
funcionalidades em seus programas construídos com os thinTemplates.
Vale ressaltar que toda a exemplificação será feita utilizando o banco de dados
Sports.

Override de métodos
Em muitas situações faz-se necessária a customização de métodos básicos
(àqueles definidos internamente nos includes padrão), a fim de facilitar este
tipo de customização foi desenvolvida esta técnica.
A técnica consiste em executar 2 (dois) métodos, sendo chamados no ponto
inicial e final de um método básico. A seguir está listada uma tabela com os
métodos que possuem override:
Método Descrição
saveFields Grava alterações feitas pelo usuário final na temp-table
de comunicação
thinMaintenance e thinMaintenanceNoNavigation
displayFields Atualiza dados da temp-table de comunicação em tela
thinMaintenance, thinMasterDetail e thinMaintenanceNoNavigation
displayWidgets Exibe widgets em tela
ThinWindow
DisableFields Desabilita campos em tela
thinMaintenance , thinMaintenanceNoNavigation e thinReport
enableFields Habilita campos em tela
thinMaintenance , thinMaintenanceNoNavigation e thinReport
enableWidgets Habilita widgets em tela
140

Método Descrição
ThinWindow
controlToolBar Seta estado dos botões/menus principais do programa
thinMaintenance e thinMasterDetail
destroyInterface Destrói programa e os DBOs principais
thinMaintenance, thinMasterDetail, thinMaintenanceNoNavigation, thinZoom ,
thinWindow e thinReport
initializeInterface Inicializa programa
thinMaintenance, thinMasterDetail, thinMaintenanceNoNavigation, thinZoom ,
thinWindow e thinReport
ChangePage Troca de página
thinMaintenance, thinMasterDetail, thinMaintenanceNoNavigation, thinZoom e
thinWindow

Para tanto deve-se utilizar uma nomenclatura específica para a definição dos
métodos de override. A seguir é exibida a regra de nomenclatura:
<before/after><nome-do-método-básico>
Exemplo de override do método displayFields:
PROCEDURE beforeDisplayFields:
/*-----------------------------------------------------------------
Purpose: Override do método displayFields (before)
Parameters:
Notes:
-----------------------------------------------------------------*/
RETURN "OK":U.
END PROCEDURE.
PROCEDURE afterDisplayFields:
/*-----------------------------------------------------------------
Purpose: Override do método displayFields (after)
Parameters:
Notes:
-----------------------------------------------------------------*/
RETURN "OK":U.
END PROCEDURE.

Neste exemplo o primeiro método (beforeDisplayFields) é executado


antes do código principal do método displayFields, e o segundo método
(afterDisplayFields) é executado após o código principal do método
displayFields.
Além disso, nestes métodos deve-se utilizar o comando RETURN "OK":U para
indicar que o método básico não deve ser cancelado, e o comando RETURN
"NOK":U para indicar que o método básico deve ser cancelado.
CAPÍTULO 10 Técnicas 141

Pesquisa de chaves estrangeiras


Em muitas situações faz-se necessária a implementação de pesquisa de campos
que representam chaves estrangeiras. Para tanto devem ser seguidas algumas
regras, descritas a seguir:
 deve ser incluso ao lado do campo que representa a chave estrangeira, 1
(um) fill-in para conter a descrição desta, seguindo as regras de
implementação de widgets do template;
 nas triggers de MOUSE-SELECT-DBLCLICK e F5 devem ser feito uso do
include method/ZoomFields.i;
 setar o cursor de pesquisa (image/lupa.cur) para o campo que
representa a chave estrangeira.
A imagem a seguir exibe como ficam os campos que representam chave
estrangeira, em desenvolvimento:

A tabela a seguir contém os parâmetros a serem utilizados no include


method/ZoomFields.i:
Parâmetro Descrição
ProgramZoom Nome do programa de Pesquisa a ser executado
FieldZoomN Indica o nome do campo que deve ser retornado pelo
programa de Pesquisa, N indica um número que pode
variar de 1 até 10
FieldScreenN Indica o nome do campo (variável) que deve receber o
valor retornado pelo programa de pesquisa, N indica
um número que pode variar de 1 até 10
FrameN Indica o nome da frame na qual está o campo (variável)
que deve receber o valor retornado pelo programa de
pesquisa, N indica um número que pode variar de 1 até
10
FieldHandleN Indica a variável handle que contém o handle do
campo que deve receber o valor retornado pelo
programa de pesquisa, N indica um número que pode
variar de 1 até 10, não se deve utilizar este parâmetro
em conjunto com os parâmetros FieldZoomN,
FieldScreenN e FrameN
142

Parâmetro Descrição
RunMethod Indica a linha de comando, que contém a chamada a
um método do programa de pesquisa
A variável hProgramZoom contém o handle do
programa de pesquisa
EnableImplant Os valores YES e NO indicam se o botão Implantar
será habilitado ou não.

Exemplo de código com o preenchimento dos parâmetros:


OR F5 OF ttCustomer.Sales-Rep IN FRAME fPage2 DO:
{method/ZoomFields.i &ProgramZoom="C:/program/SalesRepZoom.w"
&FieldZoom1="Sales-Rep"
&FieldScreen1="ttCustomer.Sales-Rep"
&Frame1="fPage2"
&FieldZoom2="Rep-Name"
&FieldScreen2="fiRepName"
&Frame2="fPage2"
&RunMethod="RUN setaVariable IN
hProgramZoom (INPUT 'Representante')."
&EnableImplant="NO"}
END.

Além disso, deve-se setar o cursor do mouse para lupa, para tanto deve-se
utilizar a lógica a seguir na sessão Main Block do programa:
/*--- Seta cursor do mouse para lupa, quando estiver posicionado
sobre o fill-in ---*/
ttCustomer.Sales-Rep:LOAD-MOUSE-POINTER("image/lupa.cur":U)
IN FRAME fPage2.

Pesquisa de chaves estrangeiras em Browses


Em muitas situações faz-se necessária a implementação de pesquisa de campos
que representam chaves estrangeiras em browses. Para tanto devem ser
seguidas algumas regras, descritas a seguir:
 deve ser incluso ao lado do campo que representa a chave estrangeira, 1
(uma) variável para conter a descrição desta, seguindo as regras de
implementação de widgets do template;
 nas triggers de MOUSE-SELECT-DBLCLICK e F5 devem ser feito uso do
include method/ZoomFields.i.
CAPÍTULO 10 Técnicas 143

A imagem a seguir exibe como ficam os campos que representam chave


estrangeira, em desenvolvimento:

A tabela a seguir contém os parâmetros a serem utilizados no include


method/ZoomFields.i:
Parâmetro Descrição
ProgramZoom Nome do programa de Pesquisa a ser executado
FieldZoomN Indica o nome do campo que deve ser retornado pelo
programa de Pesquisa, N indica um número que pode
variar de 1 até 10
FieldScreenN Indica o nome do campo (variável) que deve receber o
valor retornado pelo programa de pesquisa, N indica
um número que pode variar de 1 até 10
BrowseN Indica o nome do browse no qual está o campo
(variável) que deve receber o valor retornado pelo
programa de pesquisa, N indica um número que pode
variar de 1 até 10
FieldHandleN Indica a variável handle que contém o handle do
campo que deve receber o valor retornado pelo
programa de pesquisa, N indica um número que pode
variar de 1 até 10, não se deve utilizar este parâmetro
144

Parâmetro Descrição
em conjunto com os parâmetros FieldZoomN,
FieldScreenN e FrameN
RunMethod Indica a linha de comando, que contém a chamada a
um método do programa de pesquisa
A variável hProgramZoom contém o handle do
programa de pesquisa
EnableImplant Os valores YES e NO indicam se o botão Implantar
será habilitado ou não.

Exemplo de código com o preenchimento dos parâmetros:


OR F5 OF ttCustomer.Sales-Rep IN BRWSE brUpd1 DO:
{method/ZoomFields.i &ProgramZoom="C:/program/SalesRepZoom.w"
&FieldZoom1="Sales-Rep"
&FieldScreen1="ttCustomer.Sales-Rep"
&Browse1="brUpd1"
&FieldZoom2="Rep-Name"
&FieldScreen2="cRepName"
&Browse2="brUpd1"
&RunMethod="RUN setaVariable IN
hProgramZoom (INPUT 'Representante')."
&EnableImplant="NO"}
END.

Pesquisa de chaves estrangeiras com SmartZoom


Em muitas situações faz-se necessária a implementação de pesquisa de campos
que representam chaves estrangeiras e já se possui um programa que atende a
necessidade, mas o mesmo está construído em SmartObjects. Sendo assim, é
desnecessário construir um novo ThinZoom, deve-se apenas seguir algumas
regras, descritas a seguir:
 deve ser incluso ao lado do campo que representa a chave estrangeira, 1
(um) fill-in para conter a descrição desta, seguindo as regras de
implementação de widgets do template;
 definir variáveis que são utilizadas pela tecnologia smartObjects;
 nas triggers de MOUSE-SELECT-DBLCLICK e F5 devem ser feito uso do
include include/zoomvar.i;
 setar o cursor de pesquisa (image/lupa.cur) para o campo que
representa a chave estrangeira.
CAPÍTULO 10 Técnicas 145

A imagem a seguir exibe como ficam os campos que representam chave


estrangeira, em desenvolvimento:

Definir as duas variáveis a seguir na seção Definitions do programa:


DEFINE NEW GLOBAL SHARED VARIABLE adm-broker-hdl AS HANDLE NO-UNDO.
DEFINE VARIABLE wh-pesquisa AS HANDLE NO-UNDO.

A tabela a seguir contém os parâmetros a serem utilizados no include


include/zoomvar.i:
Parâmetro Descrição
prog-zoom Nome do programa de Pesquisa a ser executado.
Campo Indica o nome do campo que deve ser retornado pelo
programa de Pesquisa. Caso seja utilizado para mais
de um campo, deve-se informar, a partir do segundo
campo, um número seqüencial.
Campozoom Indica o nome do campo no SmartBrowser do zoom de
onde o valor é buscado, não deve ser informado o
nome da tabela. Caso seja utilizado para mais de um
campo, deve-se informar, a partir do segundo campo,
um número seqüencial.
Frame Indica o nome da frame na qual está o campo (variável)
que deve receber o valor retornado pelo programa de
pesquisa. Este parâmetro é opcional em SmartObjects,
mas deve ser utilizado em ThinTemplates. Caso seja
utilizado para mais de um campo, deve-se informar, a
partir do segundo campo, um número seqüencial.
Parametros Indica a linha de comando, que contém a chamada a
um método do programa de pesquisa
A variável wh-pesquisa contém o handle do programa
de pesquisa.

Exemplo de código com o preenchimento dos parâmetros:


OR F5 OF ttCustomer.Sales-Rep IN FRAME fPage2 DO:
{include/zoomvar.i &prog-zoom="C:/program/SalesRepZoom.w"
&campo="ttCustomer.Sales-Rep"
&campozoom="Sales-Rep"
&frame="fPage2"}
END.
146

Além disso, deve-se setar o cursor do mouse para lupa, para tanto deve-se
utilizar a lógica a seguir na sessão Main Block do programa:
/*--- Seta cursor do mousr para lupa, quando estiver posicionado
sobre o fill-in ---*/
ttCustomer.Sales-Rep:LOAD-MOUSE-POINTER("image/lupa.cur":U) IN
FRAME fPage2.

Referências para chaves estrangeiras


Em muitas situações faz-se necessária a implementação de referências para
chaves estrangeiras. Para tanto devem ser seguidas algumas regras, descritas a
seguir:
 deve ser incluso ao lado do campo que representa a chave estrangeira, 1
(um) fill-in para conter a descrição desta, seguindo as regras de
implementação de widgets do template;
 instância do programa DBO que contém acesso à tabela que contém a
descrição do campo que representa a chave estrangeira;
 na trigger de LEAVE deve ser feito uso do include
method/ReferenceFields.i;

 override do método de displayFields (after);


 eliminar instância do programa DBO através de override do método de
destroyInterface (after).
A imagem a seguir exibe como ficam os campos que representam chave
estrangeira, em desenvolvimento:

A instância do programa DBO, que contém acesso à tabela que contém a


descrição do campo que representa a chave estrangeira, deve ser feita no
método initializeDBOs.
Os includes a seguir devem ser utilizados para realizar a instância do programa
DBO:
{btb/btb008za.i1 <DBOProgram> YES}
{btb/btb008za.i2 <DBOProgram> '' <VariableHandle>}
RUN openQueryStatic IN THIS-PROCEDURE (INPUT "<Query>":U) NO-ERROR.
CAPÍTULO 10 Técnicas 147

A tabela a seguir contém os parâmetros a serem utilizados para a instância do


programa DBO:
Parâmetro Descrição
DBOProgram Nome físico do programa DBO
VariableHandle Identifica o nome da variável handle que conterá o
handle do programa DBO
Query Nome da query a ser utilizada para a abertura de query
inicial do programa DBO

Exemplo de código com o preenchimento dos parâmetros:


{btb/btb008za.i1 C:/TMP/Programs/DBOSales-Rep.p YES}
{btb/btb008za.i2 C:/TMP/Programs/DBOSales-Rep.p '' hDBOSales-Rep}
RUN openQueryStatic IN THIS-PROCEDURE (INPUT "Sales-Rep":U) NO-ERROR.

É necessária, ainda, a definição da variável hDBOSales-Rep na sessão


Definitions do programa. E em algumas situações pode ser necessária a
execução de restrições iniciais.

A tabela a seguir contém os parâmetros a serem utilizados no include


method/ReferenceFields.i:
Parâmetro Descrição
HandleDBOLeave Indica a variável handle que contém o handle do
programa DBO que contém acesso à tabela que
contém a descrição do campo que representa a chave
estrangeira
KeyValueN Indica o valor da chave a ser utilizada pelo método
goToKey, N indica um número que pode variar de 1 até
10
FieldNameN Indica o nome do campo a ser retornado pelo programa
DBO, N indica um número que pode variar de 1 até 10
FieldScreenN Indica o nome do campo (variável) que deve receber o
valor retornado pelo programa DBO, N indica um
número que pode variar de 1 até 10
FrameN Indica o nome da frame na qual está o campo (variável)
que deve receber o valor retornado pelo programa
DBO, N indica um número que pode variar de 1 até 10
ExcludeVars Indica se as variáveis utilizadas pelo include devem ser
ou não definido, este é um parâmetro opcional
(normalmente é utilizado em procedure internas
148

Parâmetro Descrição
quando deseja-se fazer mais de uma chamada ao
include)

Exemplo de código com o preenchimento dos parâmetros:


ON LEAVE OF ttCustomer.Sales-Rep IN FRAME fPage2 DO:
{method/ReferenceFields.i
&HandleDBOLeave="hDBOSalesRep"
&KeyValue1="ttCustomer.Sales-Rep:SCREEN-VALUE IN FRAME fPage2"
&FieldName1="Rep-Name"
&FieldScreen1="fiRepName"
&Frame1="fPage2"}
END.

Utilizando a técnica de Override de métodos, utilizar o ponto after para o


método displayFields, implementando a referência para chave estrangeira.
Exemplo de código:
PROCEDURE afterDisplayFields:
/*-----------------------------------------------------------------
Purpose: Override do método displayFields (after)
Parameters:
Notes:
-----------------------------------------------------------------*/

APPLY "LEAVE":U TO ttCustomer.Sales-Rep IN FRAME fPage2.

RETURN "OK":U.
END PROCEDURE.

Utilizando a técnica de Override de métodos, utilizar o ponto after para o


método destroyInterface, implementando a eliminação da instância do
programa DBO.
Exemplo de código:
PROCEDURE afterDestroyInterface:
/*-----------------------------------------------------------------
Purpose: Override do método destroyInterface (after)
Parameters:
Notes:
-----------------------------------------------------------------*/

IF VALID-HANDLE(hDBOSalesRep)
RUN destroy IN hDBOSalesRep.
CAPÍTULO 10 Técnicas 149

RETURN "OK":U.
END PROCEDURE.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
métodos disponíveis nesta versão. Além disso, o desenvolvedor deve usar o
preprocessador DBOVersion a fim de permitir fácil migração do programa
para o DBO 2.0.
A seguir modelo de instância de BO 1.1, preparado para migração:
{btb/btb008za.i1 C:/TMP/Programs/DBOSales-Rep.p YES}
{btb/btb008za.i2 C:/TMP/Programs/DBOSales-Rep.p '' hDBOSales-Rep}
&IF DEFINED(DBOVersion) <> 0 &THEN
RUN openQuery IN hDBOSalesRep (INPUT 1).
&ELSE
RUN openQueryStatic IN hDBOSalesRep (INPUT "Sales-Rep":U).
&ENDIF

A seguir modelo de eliminação de instância de BO 1.1, preparado para


migração:
&IF DEFINED(DBOVersion) <> 0 &THEN
IF VALID-HANDLE(hDBOSalesRep)
DELETE PROCEDURE hDBOSalesRep.
&ELSE
IF VALID-HANDLE(hDBOSalesRep)
RUN destroy IN hDBOSalesRep.
&ENDIF

Além da instância do BO 1.1, deve-se utilizar um novo parâmetro ao usar-se o


include method/ReferenceFields.i. Este novo parâmetro chama-se
findMethod e deve possuir o nome do método de procura do registro.
A seguir modelo de uso do include com o novo parâmetro:
ON LEAVE OF ttCustomer.Sales-Rep IN FRAME fPage2 DO:
{method/ReferenceFields.i
&HandleDBOLeave="hDBOSalesRep"
&FindMethod="findSales-Rep"
&KeyValue1="ttCustomer.Sales-Rep:SCREEN-VALUE IN FRAME fPage2"
&FieldName1="Rep-Name"
&FieldScreen1="fiRepName"
&Frame1="fPage2"}
END.
150

Referências para chaves estrangeiras em Browses


Em muitas situações faz-se necessária a implementação de referências para
chaves estrangeiras em browses. Para tanto devem ser seguidas algumas
regras, descritas a seguir:
 definir uma variável para conter a descrição do campo que representa a
chave estrangeira;
 definir uma função para retornar a descrição do campo que representa a
chave estrangeira, utilizando o include method/ReferenceFields.i;
 instânciar o programa DBO que contém acesso à tabela que contém a
descrição do campo que representa a chave estrangeira;
 incluir a variável na lista de campos exibidos pelo browse, fazendo uso da
função recém criada através do operador @, através do botão de campos
calculados;
 eliminar instância do programa DBO através de override do método de
destroyInterface (after).
A definição da variável para conter a descrição do campo que representa a
chave estrangeira deve ser feita na sessão Definitions do programa.
Exemplo de código com a definição da variável:
/* Local Variable Definitions --- */
DEFINE VARIABLE cRep-Name AS CHARACTER NO-UNDO.

A função definida pelo desenvolvedor deve receber como parâmetro o valor do


campo que representa a chave estrangeira. E fazendo uso do include
method/ReferenceFields.i deve retornar a descrição do campo que
representa a chave estrangeira.
A tabela a seguir contém os parâmetros a serem utilizados no include
method/ReferenceFields.i:
Parâmetro Descrição
HandleDBOLeave Indica a variável handle que contém o handle do
programa DBO que contém acesso à tabela que
contém a descrição do campo que representa a chave
estrangeira
KeyValueN Indica o valor da chave a ser utilizada pelo método
CAPÍTULO 10 Técnicas 151

Parâmetro Descrição
goToKey, N indica um número que pode variar de 1 até
10
FieldNameN Indica o nome do campo a ser retornado pelo programa
DBO, N indica um número que pode variar de 1 até 10
VariableN Indica o nome da variável que deve receber o valor
retornado pelo programa DBO, N indica um número
que pode variar de 1 até 10
ExcludeVars Indica se as variáveis utilizadas pelo include devem ser
ou não definido, este é um parâmetro opcional
(normalmente é utilizado em procedure internas
quando deseja-se fazer mais de uma chamada ao
include)

Exemplo de código com o preenchimento dos parâmetros:


FUNCTION fnRep-Name RETURNS CHARACTER
(INPUT pcSales-Rep AS CHARACTER) :

DEFINE VARIABLE cRep-NameAux AS CHARACTER NO-UNDO.

{method/ReferenceFields.i
&HandleDBOLeave="hDBOSalesRep"
&KeyValue1="pcSales-Rep"
&FieldName1="Rep-Name"
&Variable1="cRep-NameAux"}

RETURN cRep-NameAux.
END FUNCTION.

A instância do programa DBO, que contém acesso à tabela que contém a


descrição do campo que representa a chave estrangeira, deve ser feita no
método initializeDBOs.
Os includes a seguir devem ser utilizados para realizar a instância do programa
DBO:
{btb/btb008za.i1 <DBOProgram> YES}
{btb/btb008za.i2 <DBOProgram> '' <VariableHandle>}
RUN openQueryStatic IN THIS-PROCEDURE (INPUT "<Query>":U) NO-ERROR.

A tabela a seguir contém os parâmetros a serem utilizados para a instância do


programa DBO:
Parâmetro Descrição
DBOProgram Nome físico do programa DBO
152

Parâmetro Descrição
VariableHandle Identifica o nome da variável handle que conterá o
handle do programa DBO
Query Nome da query a ser utilizada para a abertura de query
inicial do programa DBO

Exemplo de código com o preenchimento dos parâmetros:


{btb/btb008za.i1 C:/TMP/Programs/DBOSales-Rep.p YES}
{btb/btb008za.i2 C:/TMP/Programs/DBOSales-Rep.p '' hDBOSales-Rep}
RUN openQueryStatic IN THIS-PROCEDURE (INPUT "Sales-Rep":U) NO-ERROR.

É necessária, ainda, a definição da variável hDBOSales-Rep na sessão


Definitions do programa. E em algumas situações pode ser necessária a
execução de restrições iniciais.

Utilizando o botão de campos calculados deve-se incluir a variável, que


conterá a descrição do campo que representa a chave estrangeira, no browse
fazendo uso da função recém criada e do operador @.
Exemplo da definição do campo calculado:
CAPÍTULO 10 Técnicas 153

Utilizando a técnica de Override de métodos, utilizar o ponto after para o


método destroyInterface, implementando a eliminação da instância do
programa DBO.
Exemplo de código:
PROCEDURE afterDestroyInterface:
/*-----------------------------------------------------------------
Purpose: Override do método destroyInterface (after)
Parameters:
Notes:
-----------------------------------------------------------------*/

IF VALID-HANDLE(hDBOSalesRep)
RUN destroy IN hDBOSalesRep.

RETURN "OK":U.
END PROCEDURE.

Compatibilidade com BO 1.1


Caso o desenvolvedor opte por utilizar um BO versão 1.1, deve-se utilizar
métodos disponíveis nesta versão. Além disso, o desenvolvedor deve usar o
preprocessador DBOVersion a fim de permitir fácil migração do programa
para o DBO 2.0.
A seguir modelo de instância de BO 1.1, preparado para migração:
{btb/btb008za.i1 C:/TMP/Programs/DBOSales-Rep.p YES}
{btb/btb008za.i2 C:/TMP/Programs/DBOSales-Rep.p '' hDBOSales-Rep}
&IF DEFINED(DBOVersion) <> 0 &THEN
RUN openQuery IN hDBOSalesRep (INPUT 1).
&ELSE
RUN openQueryStatic IN hDBOSalesRep (INPUT "Sales-Rep":U).
&ENDIF

A seguir modelo de eliminação de instância de BO 1.1, preparado para


migração:
&IF DEFINED(DBOVersion) <> 0 &THEN
IF VALID-HANDLE(hDBOSalesRep)
DELETE PROCEDURE hDBOSalesRep.
&ELSE
IF VALID-HANDLE(hDBOSalesRep)
RUN destroy IN hDBOSalesRep.
&ENDIF

Além da instância do BO 1.1, deve-se utilizar um novo parâmetro ao usar-se o


include method/ReferenceFields.i. Este novo parâmetro chama-se
findMethod e deve possuir o nome do método de procura do registro.
A seguir modelo de uso do include com o novo parâmetro:
154

FUNCTION fnRep-Name RETURNS CHARACTER


(INPUT pcSales-Rep AS CHARACTER) :

DEFINE VARIABLE cRep-NameAux AS CHARACTER NO-UNDO.

{method/ReferenceFields.i
&HandleDBOLeave="hDBOSalesRep"
&FindMethod="findSales-Rep"
&KeyValue1="pcSales-Rep"
&FieldName1="Rep-Name"
&Variable1="cRep-NameAux"}

RETURN cRep-NameAux.
END FUNCTION.

Campos indicadores (combo-box, selection-list ou radio-set)


Em muitas situações é preciso exibir para o usuário final uma lista de opções
(seja esta exibida em um combo-box, selection-list ou radio-set) a fim de
facilitar a entrada de dados.
Nestes casos, normalmente o valor exibido em tela não é aquele que é gravado
no banco de dados, por exemplo:
Descrição Valor no banco de dados
Feminino F
Masculino M

Quando isto acontece, definimos o widget que apresenta a lista como um


campo indicador.
Para implementar um campo indicador devem ser seguidas algumas regras,
descritas a seguir:
 deve ser incluso 1 (um) widget que irá conter a lista de opções (combo-
box, selection-list ou radio-set), caso seja um radio-set ou list-box deve-se
incluí-lo dentro de um retângulo com label; além disso devem ser seguidas
as regras de implementação de widgets do template;
 instância do programa DBO que contém acesso à tabela de origem das
informações da lista, caso necessário;
 override do método de displayFields (after);
 override do método de saveFields (after).
CAPÍTULO 10 Técnicas 155

A imagem a seguir exibe um exemplo de campo indicador, em


desenvolvimento:

A instância do programa DBO, que contém acesso à tabela de origem das


informações da lista, caso necessário, deve ser feita no método
initializeDBOs.
Os includes a seguir devem ser utilizados para realizar a instância do programa
DBO:
{btb/btb008za.i1 <DBOProgram> YES}
{btb/btb008za.i2 <DBOProgram> '' <VariableHandle>}
RUN openQueryStatic IN THIS-PROCEDURE (INPUT "<Query>":U) NO-ERROR.

A tabela a seguir contém os parâmetros a serem utilizados para a instância do


programa DBO:
Parâmetro Descrição
DBOProgram Nome físico do programa DBO
VariableHandle Identifica o nome da variável handle que conterá o
handle do programa DBO
Query Nome da query a ser utilizada para a abertura de query
inicial do programa DBO

Exemplo de código com o preenchimento dos parâmetros:


{btb/btb008za.i1 C:/TMP/Programs/DBOState.p YES}
{btb/btb008za.i2 C:/TMP/Programs/DBOState.p '' hDBOState}
RUN openQueryStatic IN THIS-PROCEDURE (INPUT "State":U) NO-ERROR.

É necessária, ainda, a definição da variável hDBOState na sessão


Definitions do programa. E em algumas situações pode ser necessária a
execução de restrições iniciais.
No exemplo utilizado, não é feito uso de DBO para atualizar a lista de opções.

Utilizando a técnica de Override de métodos, utilizar o ponto after para o


método displayFields, implementando a seleção da opção correta na lista
(neste caso um radio-set) com base no valor do banco de dados.
156

Exemplo de código:
PROCEDURE afterDisplayFields:
/*-----------------------------------------------------------------
Purpose: Override do método displayFields (after)
Parameters:
Notes:
-----------------------------------------------------------------*/

IF AVAILABLE ttCustomer THEN


ASSIGN rsTerms:SCREEN-VALUE IN FRAME fPage2 =
ttCustomer.Terms.

RETURN "OK":U.
END PROCEDURE.

Utilizando a técnica de Override de métodos, utilizar o ponto after para o


método saveFields, implementando a transferência dos dados do campo
indicador para o seu campo correspondente no banco de dados.
Exemplo de código:
PROCEDURE afterSaveFields:
/*-----------------------------------------------------------------
Purpose: Override do método saveFields (after)
Parameters:
Notes:
-----------------------------------------------------------------*/

ASSIGN ttCustomer.Terms = rsTerms.

RETURN "OK":U.
END PROCEDURE.

Exibir Mensagens de Erro Ocorridas


Em muitas situações é necessário exibir a tela de "Mensagens de Erro
Ocorridas". Além de exibir mensagens de erro ocorridas, pode-se utilizar para
exibir mensagens do tipo Information ou Warning. A imagem a seguir exibe a
tela do utilitário:
CAPÍTULO 10 Técnicas 157

A principal característica deste utilitário é a utilização da temp-table


RowObject para o preenchimento das linhas do browse.
Para exibir a tela de Mensagens de Erro Ocorridas devem ser seguidas
algumas regras, descritas a seguir:
 instanciar o Utilitário, através do include method/ShowMessage.i1;
 popular a temp-table RowErrors, normalmente através da execução do
método getRowErrors do programa DBO;
 transferir e exibir os dados da temp-table RowErrors para o utilitário,
através do include method/ShowMessage.i2;
 eliminar a instância do Utilitário; caso seja utilizado um thinTemplate
deve-se fazer o override do método de destroyInterface (after).

A instância do Utilitário deve ser feita da forma a seguir:


{method/ShowMessage.i1}

Para popular a temp-table RowErrors normalmente é executado o método a


seguir:
RUN getRowErrors IN <DBOHandle> (OUTPUT TABLE RowErrors).

A transferência e exibição dos dados da temp-table RowObject deve ser feita


da forma a seguir:
158

{method/ShowMessage.i2}

Caso seja necessário que o Utilitário funcione como uma janela modal, deve-
se utilizar o parâmetro &Modal com valor YES, conforme modelo a seguir:
{method/ShowMessage.i2 &Modal="YES"}

Utilizando a técnica de Override de métodos, utilizar o ponto after para o


método destroyInterface, incluindo a chamada ao include
method/ShowMessage.i3.
Exemplo de código:
PROCEDURE afterDestroyInteface:
/*-----------------------------------------------------------------
Purpose: Override do método destroyInterface (after)
Parameters:
Notes:
-----------------------------------------------------------------*/

{method/ShowMessage.i3}

RETURN "OK":U.
END PROCEDURE.

Reposicionamento Automático do Browser de Zoom


Observação Somente implementar a técnica nas variáveis INICIAL de faixa, cujo tipo de
dado for CARACTER ou INTEIRO.

 editar o programa de zoom e selecionar a variável inicial de faixa (no


exemplo c-inicial);
CAPÍTULO 10 Técnicas 159

 criar um gatilho para o evento ANY-KEY destas variáveis. Na chamada


do include AnyKey.i existe dois preprocessadores: &Variavel - que deve
conter o nome da variável inicial de faixa e &PageNumber – que receberá
o número da página:

 salvar e fechar o Programa de Zoom.

Utilização de OCX
Quando for necessária a utilização de OCX com thinTemplates é necessário
que todas as FRAMEs existentes no programa tenham a opção NO-BOX
selecionada. Veja a imagem a seguir:
160
CAPÍTULO 10 Técnicas 161

Override de eventos do browse no template MasterDetail e Zoom


Em muitas situações faz-se necessária a customização de eventos padrões do
browse, para viabilizar este tipo de customização sem interferir na execução
das DPC’s, foi desenvolvida esta técnica. Para tanto devem ser seguidas
algumas regras, descritas a seguir:
 Definir um preprocessador com o nome do evento que deseja customizar,
definindo seu valor como YES. Não utilizar o nome da include, e sim o
nome do evento como no progress. Os eventos disponíveis são: cursor-
down, end, off-end, page-down, value-changed, mouse-select-dblclick,
cursor-up, home, off-home e page-up;
Preprocessor Descrição
<evento>N Onde <evento> é o nome do evento que será
customizado no filho N, N indica o número da página,
podendo variar de 1 até 8

 Criar as triggers dos eventos e implementar a chamada da include para a


execução das DPC’s correspondente ao evento customizado;
{masterdetail/CursorDown.i &PageNumber="1"}
{masterdetail/End.i &PageNumber="1"}
{masterdetail/OffEnd.i &PageNumber="1"}
{masterdetail/PageDown.i &PageNumber="1"}
{masterdetail/ValueChanged.i &PageNumber="1"}
{masterdetail/DblClick.i &PageNumber="1"}
{masterdetail/CursorUp.i &PageNumber="1"}
{masterdetail/Home.i &PageNumber="1"}
{masterdetail/OffHome.i &PageNumber="1"}
{masterdetail/PageUp.i &PageNumber="1"}

OBS: Estas são as includes para o MasterDetail. O template de Zoom


possui os mesmos eventos. Caso a customização seja feita para um evento do
Zoom basta colocar {Zoom/<nome_da_include>.i &PageNumber=”1”}
 A customização pode ser implementada antes ou depois da execução das
DPC’s.
Exemplo das tarefas para customização do evento Value-Changed no browse
da frame fpage1:
Incluir na sessão “Definitions” o preprocessor correspondente ao evento:
&global-define VALUE-CHANGED1 yes
162

Criar a trigger de Value-Changed do browse e incluir a chamada da include:


ON VALUE-CHANGED OF brSon1 IN FRAME fPage1
DO:
{masterdetail/ValueChanged.i &PageNumber="1"}
END.

Recursos avançados do thinFolder


O thinFolder já está implementado automaticamente nos templates onde se faz
necessário. Porém o template só faz uso dos recursos básicos.
Para que os recursos avançados possam ser utilizados, está aqui uma descrição
do que se pode fazer.
Abaixo está a descrição dos métodos disponíveis para uso:

Método Descrição
SetImage Coloca uma imagem na aba do folder, em fez de um
label
SetFolder Posiciona uma página do thinFolder
GetCurrentFolder Retorna a página corrente do Folder
SetEnabled Permite habilitar/desabilitar uma página do thinFolder
InsertFolder Inclui dinamicamente uma nova página no thinFolder
DeleteFolder Elimina dinamicamente uma página do thinFolder

Usando os A seguir está a descrição do que pode ser feito com os recursos avançados do
Recursos thinFolder:

 Posicionando uma página do Folder.


Pode-se posicionar uma determinada página do folder usando o método
SetFolder. O exemplo a seguir seta à página 2 do folder:
RUN SetFolder IN hFolder (INPUT 2).

Considerações:
 Hfolder : variável handle que representa o thinFolder.
 Primeiro parâmetro: identifica qual página a ser posicionada no Folder.
CAPÍTULO 10 Técnicas 163

 Retornando a página corrente do Folder.


Pode-se retornar a página corrente do folder usando o método
GetCurrentFolder, que retorna um valor inteiro referente a página do folder.
O exemplo a seguir retorna a página corrente do folder:
RUN GetCurrentFolder IN hFolder (OUTPUT <VARIAVEL>).

Considerações:
 HFolder: variável handle que representa o thinFolder.
 <VAR> : variável do tipo inteiro que recebe o valor referente a página
corrente do folder.

 Habilitando/Desabilitando páginas.
Uma página pode ser desabilitada e habilitada novamente usando o método
setEnabled. O exemplo a seguir desabilita a página 2 e em seguida habilita a
página 1:
RUN setEnabled IN hFolder (INPUT 2, INPUT FALSE).
RUN setEnabled IN hFolder (INPUT 1, INPUT TRUE).

Considerações:
- hFolder: variável handle que representa o thinFolder.
- Primeiro parâmetro: identifica a página a ser habilitada/desabilitada.
- Segundo parâmetro: indica se a página será habilitada (TRUE) ou
desabilitada (FALSE).

 Colocando uma imagem na aba de uma página:


No lugar do tradicional label usado para identificar uma página, pode ser posto
uma imagem. O exemplo a seguir coloca uma imagem para representar a
página 1:
RUN setImage IN hFolder (INPUT 1,
INPUT “image/im-pag1”,
164

INPUT “image/ii-pag1”).

Considerações:
- hFolder: variável handle que representa o thinFolder.
- Primeiro parâmetro: identifica a página a ter a aba alterada para imagem.
- Segundo parâmetro: indica a imagem que será utilizada quando a página
estiver selecionada.
- Terceiro parâmetro: indica a imagem que será utilizada quando a página
não estiver selecionada.

 Eliminando dinamicamente uma página:


Dependendo de determinadas condições, uma página não precisa estar
presenta. Para isso, ela pode ser eliminada. O seguinte código elimina a página
3:
RUN deleteFolder IN hFolder (INPUT 3).

Considerações:
- hFolder: variável handle que representa o thinFolder.
- Primeiro parâmetro: identifica a página a ser eliminada.

 Incluindo dinamicamente uma página:


Dependendo de determinadas condições, uma página que não estava presente
inicialmente, pode ser necessária. Para isso, ela pode ser incluída. O seguinte
código insere uma nova página após a última página:
RUN insertFolder IN hFolder (INPUT ?,
INPUT FRAME fPage0:HANDLE,
INPUT FRAME fPageX:HANDLE,
INPUT "Pag. X").

Considerações:
- hFolder: variável handle que representa o thinFolder.
- Primeiro parâmetro: identifica a posição onde a nova página será incluída.
Um valor ? insere a página após todas as outras. Um valor numérico inclui
CAPÍTULO 10 Técnicas 165

a página na posição informada e move para a direita todas as demais a


partir da posição informada.
- Segundo parâmetro: handle identificando a frame pai (principal) do
programa.
- Terceiro parâmetro: handle identificando a frame a ser colocada na página.
- Quarto parâmetro: String que será usada como label para a página.
- Para que esse recurso possa ser usado, o folder já deve ter sido inicializado
anteriormente com páginas estáticas.
Nos casos onde serã incluído dinamicamente um folder, deverá ser criado
um override de método para o método InitializeInterface para que o atributo
box da frame seja desativado.
Exemplo de código:

PROCEDURE BeforeInitializeInterface :
/*----------------------------------------------------------------------
Purpose:
Parameters: <none>
Notes:
----------------------------------------------------------------------*/

assign frame fPage1:box = no


frame fPage3:box = no.

END PROCEDURE.

Correção do tab-order no ThinReport

Originalmente, a tab-order do template de relatórios foi definida de forma


errada. Na seqüência original, a tab mudava o cursor do radio button “Destino”
direto para o botão de seleção de arquivos, ao invés de posicionar o cursor no
fill-in “Arquivo”. Esta seqüência foi corrigida no template mas para os
programas já existentes, é necessário fazer o acerto manualmente conforme a
técnica abaixo:
166

1 – Selecionar as propriedades da frame fPage6 do relatório e clicar no botão “Tab


Order”:

2 – No Tab Editor, mudar a opção “Tabbing Options” de DEFAULT para


CUSTOM. Após isso posicionar o objeto cFile imediatamente após o
rsDestiny através dos botões Move Up e Move Down:
CAPÍTULO 10 Técnicas 167

Como desenvolver para o Datasul 10

Objetivo Descrever os passos necessários para o desenvolvimento utilizando os


templates do DDK para o produto Datasul 10. Como configurar e as alterações
necessárias para novos programas e programas existentes.

Descrição As alterações são necessárias para o correto funcionamento do licenciamento


do produto e também para evitar a vulnerabilidade do sistema. O novo
licenciamento é responsável por fazer o controle de licenças do produto, este
controle é feito por módulos, onde será validado se o cliente possui permissão
para acesso.
168

Requisitos Para desenvolver para o produto Datasul 10, é necessário possuir um server do
gerenciador de licenças instalado e o foundation precisa estar inicializado.

Configurações É preciso alterar a include que possui a versão dos bancos de dados (i_dbvers.i)
inserindo o banco EMSFND. Para isso deve ser alterado a include include/i_dbvers.i
encontrada na expedição do produto para inserir a definição do préprocessador do
banco EMSFND conforme exemplo abaixo.
/* Preprocessadores que identificam os bancos do Produto
Foundation */ &GLOBAL-DEFINE emsfnd_version 1.01

Alterações Para programas novos:

Para cada novo programa criado a partir de um template do DDK, é necessário


realizar as seguintes alterações:

No inicio do programa, logo após a chamada da include i-prgvrs possui o


seguinte código:

&IF "{&EMSFND_VERSION}" >= "1.00" &THEN


{include/i-license-manager.i <programa>
<modulo>}
&ENDIF

É necessário alterar os seguintes parâmetros:

<programa>: Informar qual o nome do programa.


<módulo>: Informar qual o módulo a qual o programa pertence

Nota O codigo do módulo a ser informado deve fazer parte dos módulos contratados que estao
disponiveis na licença enviada para o cliente.

Exemplo:
&IF "{&EMSFND_VERSION}" >= "1.00" &THEN
{include/i-license-manager.i CT0301D MCT}
&ENDIF

Programas Específicos Existentes:

Para programas específicos já existentes é necessário incluir a chamada a include i-


license-manager na mão conforme exemplo abaixo.
CAPÍTULO 10 Técnicas 169

&IF "{&EMSFND_VERSION}" >= "1.00" &THEN


{include/i-license-manager.i <programa> modulo>}
&ENDIF

Sendo,

<programa>: Informar qual o nome do programa.


<módulo>: Informar qual o módulo a qual o programa pertence.

Nota O codigo do módulo a ser informado deve fazer parte dos módulos contratados que estao
disponiveis na licença enviada para o cliente.

Exemplo:
&IF "{&EMSFND_VERSION}" >= "1.00" &THEN
{include/i-license-manager.i CT0301D MCT}
&ENDIF