Manualthintemplates.pdf

  • Uploaded by: Giulia
  • 0
  • 0
  • December 2019
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Manualthintemplates.pdf as PDF for free.

More details

  • Words: 27,491
  • Pages: 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.

Definição

A arquitetura dos thinTemplates foi definida com o objetivo de separar a 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

Características

Interface

Lógica

thinTemplates

DBOs

Dados

Databases

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  padrão

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.

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

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

5

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 &GLOBAL-DEFINE Version

thinMaintenance 1.00.00.000

&GLOBAL-DEFINE Folder &GLOBAL-DEFINE InitialPage

YES 1

&GLOBAL-DEFINE FolderLabels

Personal,Financial

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

First Prev Next Last GoTo Search

YES YES YES YES YES YES

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

Add Copy Update Delete Undo Cancel Save

YES YES YES YES YES YES YES

&GLOBAL-DEFINE ttTable &GLOBAL-DEFINE hDBOTable &GLOBAL-DEFINE DBOTable

ttCustomer hDBOCustomer 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 &GLOBAL-DEFINE ExcludeBtReportsJoins

YES 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 Comunicação

Criar a temp-table que é utilizada para realizar a comunicação com o DBO. E 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

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) NOERROR. &ENDIF RETURN "OK":U. END PROCEDURE.

9

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, aconselhase 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

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 widgets nas páginas

Quando for necessário fazer a inclusão de widgets (sejam campos ou widgets comuns) deve-se primeiramente selecionar o frame de trabalho. Para tanto usase o botão:

A tela a seguir é aberta, nesta deve selecionar-se a frame desejada e clicar-se no botão que está indicado:

11

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 temptable desejada e logo após os campos a serem inclusos na frame de trabalho:

CAPÍTULO 2

Construindo o thinMaintenance

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:

Método goToRecord



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.

O método goToRecord é responsável pela função de Vá Para, 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.

13

14

A seguir existe uma tabela que possui o nome dos parâmetros e suas descrições: Parâmetro Descrição Indica o tipo de variável (c = character, d = decimal, i = integer) nomes dos campos a serem inclusos na frame de Vá Para 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_"} ASSIGN FRAME fGoToRecord:TITLE = RETURN-VALUE.

CAPÍTULO 2

Construindo o thinMaintenance

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

15

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_"} 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

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.

17

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

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

21

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 &GLOBAL-DEFINE Version

thinMasterDetail 1.00.00.000

&GLOBAL-DEFINE Folder &GLOBAL-DEFINE InitialPage

YES 1

&GLOBAL-DEFINE FolderLabels

Order

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

First Prev Next Last GoTo Search

YES YES YES YES YES YES

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

AddParent CopyParent UpdateParent DeleteParent

YES YES YES YES

&GLOBAL-DEFINE AddSon1 &GLOBAL-DEFINE CopySon1

YES YES

CAPÍTULO 3

Construindo o thinMasterDetail

23

&GLOBAL-DEFINE UpdateSon1 &GLOBAL-DEFINE DeleteSon1

YES YES

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

ttParent hDBOParent DBOParentTable DBOParentDestroy

ttCustomer hDBOCustomer Customer YES

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

ttSon1 hDBOSon1 DBOSon1Table DBOSon1Destroy

ttOrder hDBOOrder Order YES

&GLOBAL-DEFINE page0Fields &GLOBAL-DEFINE page1Browse

ttCustomer.Cust-Num ~ ttCustomer.Name 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 &GLOBAL-DEFINE Version

thinMasterDetail 1.00.00.000

&GLOBAL-DEFINE Folder &GLOBAL-DEFINE InitialPage

YES 1

&GLOBAL-DEFINE FolderLabels

Order

24

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

First Prev Next Last GoTo Search

YES YES YES YES YES YES

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

AddParent CopyParent UpdateParent DeleteParent

NO NO NO NO

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

AddSon1 CopySon1 UpdateSon1 DeleteSon1 DetailSon1

NO NO NO NO YES

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

ttParent hDBOParent DBOParentTable DBOParentDestroy

ttCustomer hDBOCustomer Customer YES

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

ttSon1 hDBOSon1 DBOSon1Table DBOSon1Destroy

ttOrder hDBOOrder Order YES

&GLOBAL-DEFINE page0Fields &GLOBAL-DEFINE page1Browse

ttCustomer.Cust-Num ~ ttCustomer.Name 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 &GLOBAL-DEFINE ExcludeBtReportsJoins

YES 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

Temp-Table de Comunicação

Criar as temp-tables que são utilizadas para realizar a comunicação com os 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 DBOs

As criações das instâncias do DBOs (DBO Pai e DBOs Filho) 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.

25

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

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) NOERROR. &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;

27

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

Disposição dos widgets nas páginas

Quando for necessário fazer a inclusão de widgets (sejam campos, widgets comuns ou browses) deve-se primeiramente selecionar o frame de trabalho. 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 temptable desejada e logo após os campos a serem inclusos na frame de trabalho:

29

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

Método openQueriesSon

Construindo o thinMasterDetail



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.

O método openQueriesSon é responsável por realizar a ligação entre o DBO 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.

31

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

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

33

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 goToRecord

O método goToRecord é responsável pela função de Vá Para da tabela pai, 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 Indica o tipo de variável (c = character, d = decimal, i = integer) nomes dos campos a serem inclusos na frame de Vá Para 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

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_"} 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

37

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_"} 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

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 &GLOBAL-DEFINE Version

thinMaintenanceNoNavigation 1.00.00.000

&GLOBAL-DEFINE Folder &GLOBAL-DEFINE InitialPage

YES 1

&GLOBAL-DEFINE FolderLabels

Others

&GLOBAL-DEFINE ttTable &GLOBAL-DEFINE hDBOTable &GLOBAL-DEFINE DBOTable

ttCustomer hDBOCustomer Customer

&GLOBAL-DEFINE page0KeyFields &GLOBAL-DEFINE page0Fields &GLOBAL-DEFINE page1Fields

ttCustomer.Cust-Num ttCustomer.Name 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)

43

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 &GLOBAL-DEFINE Version

thinMaintenanceNoNavigation 1.00.00.000

&GLOBAL-DEFINE Folder &GLOBAL-DEFINE InitialPage

YES 1

&GLOBAL-DEFINE FolderLabels

Others

&GLOBAL-DEFINE ttTable &GLOBAL-DEFINE hDBOTable &GLOBAL-DEFINE DBOTable

ttOrder hDBOOrder Order

&GLOBAL-DEFINE ttParent &GLOBAL-DEFINE DBOParent

ttCustomer 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

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 Comunicação

Criar a temp-table que é utilizada para realizar a comunicação com o DBO. E 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.

45

46

Mas caso o programa seja utilizado para manutenção de tabelas filho, devemse 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 executação do programa

Como este template é utilizado para estilos diferentes de manutenção. Deve-se definir os parâmetros como o estilo utilizado. 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 DEFINE INPUT PARAMETER prParent DEFINE INPUT PARAMETER pcAction DEFINE INPUT PARAMETER phCaller DEFINE INPUT PARAMETER piSonPageNumber

*/ AS AS AS AS AS

ROWID ROWID CHARACTER HANDLE INTEGER

NO-UNDO. NO-UNDO. NO-UNDO. NO-UNDO. 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 saveParentFields

O método saveParentFields é responsável pela atualização dos campos 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

/*--- 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, aconselhase 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);

49

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 widgets nas páginas

Quando for necessário fazer a inclusão de widgets (sejam campos ou widgets comuns) deve-se primeiramente selecionar o frame de trabalho. Para tanto usase o botão:

CAPÍTULO 4

Construindo o thinMaintenanceNoNavigation

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 temptable desejada e logo após os campos a serem inclusos na frame de trabalho:

51

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



referência para campos de chave estrangeira.

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

53

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 &GLOBAL-DEFINE Version

thinZoom 1.00.00.000

&GLOBAL-DEFINE InitialPage &GLOBAL-DEFINE FolderLabels

1 Cust-Num,Name

&GLOBAL-DEFINE Range

YES

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

sports.Customer.Cust-Num sports.Customer.Name

FieldsRangePage1 FieldsRangePage2 FieldsRangePage3 FieldsRangePage4 FieldsRangePage5 FieldsRangePage6 FieldsRangePage7 FieldsRangePage8 FieldsAnyKeyPage1 FieldsAnyKeyPage2 FieldsAnyKeyPage3 FieldsAnyKeyPage4 FieldsAnyKeyPage5 FieldsAnyKeyPage6

YES NO

58

&GLOBAL-DEFINE FieldsAnyKeyPage7 &GLOBAL-DEFINE FieldsAnyKeyPage8 &GLOBAL-DEFINE ttTable1 &GLOBAL-DEFINE hDBOTable1 &GLOBAL-DEFINE DBOTable1

ttCustomer hDBOCustomer Customer

&GLOBAL-DEFINE ttTable2 &GLOBAL-DEFINE hDBOTable2 &GLOBAL-DEFINE DBOTable2

ttCustomer2 hDBOCustomer2 Customer

&GLOBAL-DEFINE page1Browse &GLOBAL-DEFINE page2Browse

brTable1 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 Comunicação

Criar as temp-tables que são utilizadas para realizar a comunicação com os 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

Queries para os browses

A query do browser deve ser gerada com um FOR EACH simples na TEMPTABLE de comunicação da interface. Em cada página do Zoom.

59

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



caso utilize-se combo-boxs, devem possuir a altura 0.88, somente o primeiro deve possuir label e devem utilizar as imagens: image/imfir.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 DBOs

As criações das instâncias do DBOs devem ser feitas manualmente, utilizando 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}

61

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) NOERROR. &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

/*--- 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:

63

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 widgets nas páginas

Quando for necessário fazer a inclusão de widgets (sejam campos, widgets comuns ou browses) deve-se primeiramente selecionar o frame de trabalho. 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

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:

Método openQueries



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.

O método openQueries é responsável por realizar a abertura dos browsers com os dados dos DBOs. Para tanto é feito o uso do include zoom/OpenQueries.i para atualizar os dados dos browsers.

65

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

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 setConstraints

O método setConstraints é responsável por realizar a abertura dos browsers, com as restrições indicadas pelo usuário final, com os dados dos DBOs. Para tanto é feito o uso dos métodos setConstraint 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),

67

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 INPUT fnEndRangeIntPage(INPUT 1, INPUT &ELSE /*--- Seta Constraints para o DBOTable1 ---*/ RUN setConstraintCustNum IN {&hDBOTable1} (INPUT fnIniRangeIntPage(INPUT 1, INPUT INPUT fnEndRangeIntPage(INPUT 1, INPUT &ENDIF WHEN 2 THEN &IF DEFINED(DBOVersion) <> 0 &THEN /*--- Seta Constraints para o DBOTable2 ---*/ RUN setConstraint1 IN {&hDBOTable2} (INPUT fnIniRangeCharPage(INPUT 2, INPUT fnEndRangeCharPage(INPUT 2, &ELSE /*--- Seta Constraints para o DBOTable2 ---*/ RUN setConstraintName IN {&hDBOTable2} (INPUT fnIniRangeCharPage(INPUT 2, INPUT fnEndRangeCharPage(INPUT 2, &ENDIF

1), 1)).

1), 1)).

INPUT 1), INPUT 1)).

INPUT 1), INPUT 1)).

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 returnFieldsPage <PageNumber>

O método returnFieldsPage<PageNumber> é responsável por retornar os valores dos campos do registro selecionado pelo usuário final. 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

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 definidos. padrão 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.

71

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:

Páginas do folder

&GLOBAL-DEFINE Program &GLOBAL-DEFINE Version

thinMaintenance 1.00.00.000

&GLOBAL-DEFINE WindowType

Detail

&GLOBAL-DEFINE Folder &GLOBAL-DEFINE InitialPage &GLOBAL-DEFINE FolderLabels

YES 1 Local Default

&GLOBAL-DEFINE page0Widgets &GLOBAL-DEFINE page1Widgets

btOk btHelp

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, aconselhase 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

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 widgets nas páginas

Quando for necessário fazer a inclusão de widgets (sejam campos ou widgets comuns) deve-se primeiramente selecionar o frame de trabalho. Para tanto usase 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.

77

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

A seguir é apresentada tabela com os nomes dos preprocessors padrões e suas descrições: Preprocessor Program Version VersionLayout

Descrição Nome do programa – Formato (XX9999) Versão do programa – Formato (9.99.99.999) 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 PGSEL PGCLA PGPAR PGDIG PGIMP PGLOG

Indica se a página de Layout estará disponível Indica se a página de Seleção estará disonível Indica se a página de Classificação estará disponível Indica se a página de Parâmetros estará disponível Indica se a página de Digitação estará disponível Indica se a página de Impressão estará disponível 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 Page1Widgets Page2Widgets Page3Widgets Page4Widgets Page5Widgets Page6Widgets Page7Widgets Page8Widgets Page0Text Page1Text Page2Text Page3Text Page4Text Page5Text Page6Text Page7Text Page8Text Page0Fields Page1Fields Page2Fields Page3Fields

Lista de widgets disponíveis na página 0 Lista de widgets disponíveis na página 1 Lista de widgets disponíveis na página 2 Lista de widgets disponíveis na página 3 Lista de widgets disponíveis na página 4 Lista de widgets disponíveis na página 5 Lista de widgets disponíveis na página 6 Lista de widgets disponíveis na página 7 Lista de widgets disponíveis na página 8 Lista de textos disponíveis na página 0 Lista de textos disponíveis na página 1 Lista de textos disponíveis na página 2 Lista de textos disponíveis na página 3 Lista de textos disponíveis na página 4 Lista de textos disponíveis na página 5 Lista de textos disponíveis na página 6 Lista de textos disponíveis na página 7 Lista de textos disponíveis na página 8 Lista de variáveis disponíveis na página 0 Lista de variáveis disponíveis na página 1 Lista de variáveis disponíveis na página 2 Lista de variáveis disponíveis na página 3

81

82

Preprocessor Page4Fields Page5Fields Page6Fields Page7Fields Page8Fields

Descrição Lista de variáveis disponíveis na página 4 Lista de variáveis disponíveis na página 5 Lista de variáveis disponíveis na página 6 Lista de variáveis disponíveis na página 7 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 &GLOBAL-DEFINE InitialPage &GLOBAL-DEFINE FolderLabels Digitação,Impressão &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

PGLAY PGSEL PGCLA PGPAR PGDIG PGIMP PGLOG

YES 1 Seleção,Classificação,Parâmetro, NO YES YES YES YES YES NO

&GLOBAL-DEFINE RTF

YES

&GLOBAL-DEFINE page0Widgets

btOk ~ btCancel ~ btHelp2

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

page1Widgets page2Widgets page3Widgets page4Widgets

&GLOBAL-DEFINE page5Widgets

&GLOBAL-DEFINE page6Widgets

rsClassif lParameter ~ btInputFile brDigita ~ btAdd ~ btUpdate ~ btDelete ~ btSave ~ btOpen rsDestiny ~ btConfigImpr ~ btFile ~

CAPÍTULO 7

Construindo o thinReport

83

rsExecution &GLOBAL-DEFINE page7Widgets &GLOBAL-DEFINE page8Widgets

Páginas do folder

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

page0Text page1Text page2Text page3Text page4Text page5Text page6Text page7Text page8Text

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

page1Fields page2Fields page3Fields page4Fields page5Fields page6Fields page7Fields page8Fields

text-entrada text-destino text-modo

cIniField cEndField cInputFile cFile

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

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 widgets nas páginas

Quando for necessário fazer a inclusão de widgets (sejam campos ou widgets comuns) deve-se primeiramente selecionar o frame de trabalho. Para tanto usase 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.

85

86

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

Preparação do Programa (Interface)



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.

1. Verificar quais páginas é necessário ao programa. 2. Eliminar as frames das páginas desnecessárias com base na tabela acima. 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 &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

PGLAY PGSEL PGCLA PGPAR PGDIG PGIMP PGLOG

NO YES YES YES YES YES 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

{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 Classificação

1. Redefinir o 'list-items' do radio-set rs-classif , com as opções de classificação de seu relatório; 2. Se necessário adicionar mais opções de classificação.

Página de Parâmetros

Esta página é obrigatória para programas de Importação e Exportação. 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

87

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: /* /* /* /* /* /* /* /* /*

Página de Digitação

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.

*/ */ */ */ */ */ */ */ */

1. Em 'Definitions', corrigir a definição da temp-table de digitação tt-digita 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 Impressão

A página de Impressão não é necessária que se tenha qualquer função adicional para o seu correto funcionamento. Esta página somente deve ser

CAPÍTULO 7

Construindo o thinReport

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 validação dos parâmetros

1. Em 'Definitions' implementar os campos de parâmetros e seleção na definição da temp-table tt-param.

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.

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.

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 impressão/visualização do relatório e pela caixa de acompanhamento de de Relatório 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.

89

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 streamio. 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 programa RP.P de Relatório

/* include de controle de versão */ {include/i-prgvrs.i SP0014RP 1.00.00.000}

/* 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 página seleção */

LIKE customer.cust-num

/* campo

FIELD fim-cust-num página seleção */

LIKE customer.cust-num

/* campo

FIELD sales-rep página parâmetros */

LIKE salesrep.sales-rep

/* campo

.

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.ordernum)). 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.ordernum)). 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.

Exemplo de programa RP.P de Importação

/* include de controle de versão */ {include/i-prgvrs.i XX9999RP 1.00.00.000} /* definição das temp-tables para recebimento de parâmetros */ define temp-table tt-param field destino field arquivo field arq-entrada field arq-destino field usuario field data-exec field hora-exec

no-undo as integer as char format as char format as char format as char format as date as INTEGER.

"x(35)" "x(35)" "x(35)" "x(12)"

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 def def def

stream s-imp. var h-acomp as handle no-undo. var c-linha as char no-undo. 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.arqdestino}

/* 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 = c-versao = c-revisao = c-empresa = c-sistema = c-titulo-relat

"IM0001RP" "1.00" ".00.000" "Empresa Teste" 'Sports' = "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.

Exemplo programa RP.P de Exportação

/* include de controle de versão */ {include/i-prgvrs.i EX0001RP 1.00.00.000}

/* definição das temp-tables para recebimento de parâmetros */ define temp-table tt-param field destino field arq-saida field arq-destino field usuario field data-exec field hora-exec FIELD cust-ini FIELD cust-fim

no-undo as integer as char format "x(35)" as char format "x(35)" as char format "x(12)" as date as integer AS INTEGER 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.arqdestino}

/* 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 = c-versao = c-revisao = c-empresa = c-sistema = c-titulo-relat Customer".

"EX0001RP" "1.00" ".00.000" "Empresa Teste" 'Sports' = "Exportação dos Registros da Tabela

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.custnum)). 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 necessitase 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-ModelRtf



text-destino text-modo text-rtf

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 btconfig-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

SIZE 40 BY .88 BGCOLOR 15 NO-UNDO. 

Após a definição da variável text-destino(“DEFINE VARIABLE textdestino 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 textmodo 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

103

104

text-ModelRtf AT ROW 6.54 COL 1 COLON-ALIGNED NOLABEL 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 NOLABEL 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-pgimp 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 habilitaRtf

= INPUT FRAME fPage6 l-

&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 irpclo.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

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:

109

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 &GLOBAL-DEFINE Version

thinFormation 1.00.00.000

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

YES YES YES YES YES YES

First Prev Next Last GoTo Search

&GLOBAL-DEFINE UpdateTarget

YES

&GLOBAL-DEFINE DelTarget &GLOBAL-DEFINE AddTarget &GLOBAL-DEFINE DelAllTarget

YES YES YES

112

&GLOBAL-DEFINE AddAllTarget

YES

&GLOBAL-DEFINE ttParent &GLOBAL-DEFINE hDBOParent &GLOBAL-DEFINE DBOParentTable

ttOrder hDBOOrder Order

&GLOBAL-DEFINE ttTarget &GLOBAL-DEFINE hDBOTarget &GLOBAL-DEFINE DBOTargetTable

ttOrder-Line hDBOOrder-Line Order-Line

&GLOBAL-DEFINE ttSource &GLOBAL-DEFINE hDBOSource &GLOBAL-DEFINE DBOSourceTable

ttItem hDBOItem Item

&GLOBAL-DEFINE page0Fields

ttOrder.Order-Num ~ ttOrder.Order-Date ~ ttOrder.Sales-Rep brSource brTarget

&GLOBAL-DEFINE sourceBrowse &GLOBAL-DEFINE targetBrowse

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 &GLOBAL-DEFINE ExcludeBtReportsJoins

YES 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

Temp-Table de Comunicação

Criar as temp-tables que são utilizadas para realizar a comunicação com os 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 browses

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

113

114

Instâncias do DBOs

As criações das instâncias do DBOs (DBO Pai, DBO Origem e DBO Destino) 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

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:

115

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 Comunicação

Para inclusão dos 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 temptable desejada e logo após os campos a serem inclusos na frame de trabalho:

CAPÍTULO 8

Construindo o thinFormation

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 openQueries

O método openQueries é responsável por realizar a ligação entre o DBO Pai 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.

117

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

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.

119

120

Save Parent Fields

O método saveParentFields é responsável por atualizar a tabela de 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 definidos. padrão 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



Trigger de Choose para o botão btSearch

121

:

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 goToRecord

O método goToRecord é responsável pela função de Vá Para da tabela pai, 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 Indica o tipo de variável (c = character, d = decimal, i = integer) nomes dos campos a serem inclusos na frame de Vá Para 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_"} 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

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_"} 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.

123

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



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

125

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

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

127

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 &GLOBAL-DEFINE Version

thinFormationNoNavigation 1.00.00.000

&GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE &GLOBAL-DEFINE

DelTarget AddTarget DelAllTarget AddAllTarget

YES YES YES YES

&GLOBAL-DEFINE UpdateTarget

YES

&GLOBAL-DEFINE ttParent &GLOBAL-DEFINE hDBOParent &GLOBAL-DEFINE DBOParentTable

ttOrder hDBOOrder Order

&GLOBAL-DEFINE ttTarget &GLOBAL-DEFINE hDBOTarget &GLOBAL-DEFINE DBOTargetTable

ttOrder-Line hDBOOrder-Line Order-Line

&GLOBAL-DEFINE ttSource &GLOBAL-DEFINE hDBOSource &GLOBAL-DEFINE DBOSourceTable

ttItem hDBOItem Item

&GLOBAL-DEFINE page0Fields

ttOrder.Order-Num ~ ttOrder.Order-Date ~ ttOrder.Sales-Rep brSource brTarget

&GLOBAL-DEFINE sourceBrowse &GLOBAL-DEFINE targetBrowse

CAPÍTULO 9

Construindo o thinFormationNoNavigation

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 Comunicação

Criar as temp-tables que são utilizadas para realizar a comunicação com os 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.

129

130

Instâncias do DBOs

As criações das instâncias do DBOs (DBO Pai, DBO Origem e DBO Destino) 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

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:

131

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 Comunicação

Para inclusão dos 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 temptable desejada e logo após os campos a serem inclusos na frame de trabalho:

CAPÍTULO 9

Construindo o thinFormationNoNavigation

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 openQueries

O método openQueries é responsável por realizar a ligação entre o DBO Pai 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.

133

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

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"

135

136

&OpenAlways="no"} RETURN "OK":U. END PROCEDURE.

Save Parent Fields

O método saveParentFields é responsável por atualizar a tabela de 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 definidos. padrão 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

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

137

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: <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

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

141

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

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

143

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

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.

145

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 YES} {btb/btb008za.i2 '' } RUN openQueryStatic IN THIS-PROCEDURE (INPUT "":U) NO-ERROR.

CAPÍTULO 10

Técnicas

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

147

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

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.

149

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

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 YES} {btb/btb008za.i2 '' } RUN openQueryStatic IN THIS-PROCEDURE (INPUT "":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

151

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

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:

153

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 (combobox, 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

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 YES} {btb/btb008za.i2 '' } RUN openQueryStatic IN THIS-PROCEDURE (INPUT "":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.

155

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

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 (OUTPUT TABLE RowErrors).

A transferência e exibição dos dados da temp-table RowObject deve ser feita da forma a seguir:

157

158

{method/ShowMessage.i2}

Caso seja necessário que o Utilitário funcione como uma janela modal, devese 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



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:

159

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: cursordown, 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 Recursos

A seguir está a descrição do que pode ser feito com os recursos avançados do 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 ).

Considerações: 

HFolder: variável handle que representa o thinFolder.



: 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

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:

165

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

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.

167

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 ilicense-manager na mão conforme exemplo abaixo.

CAPÍTULO 10

Técnicas

&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

169

More Documents from "Giulia"