Criando visualização de texto com número de linha e pesquisa | Ti Responde 0112

No vídeo de hoje, vamos demonstrar em como criar uma tela em AdvPL que mostre um texto de log (similar a ShowLog e MostraErro) mas com número de linhas e opção de pesquisar com Ctrl+F.

A dúvida de hoje, nos perguntaram, se seria possível criar uma tela para visualizar logs de forma mais amigável, com pesquisa e número de linhas.

 

Pensando nisso, montamos esse exemplo, onde demonstramos em como criar a tela usando recursos de navegação HTML.

 

Segue abaixo o vídeo exemplificando:

 

E abaixo o código fonte desenvolvido:

//Bibliotecas
#Include "TOTVS.ch"

/*/{Protheus.doc} zVid0112
Fonte demonstrando em como acionar a zTiLog
@type user function
@author Atilio
@since 25/01/2024
/*/

User Function zVid0112()
    Local aArea  := FWGetArea()
    Local cTexto := ""
    Local cQuery := ""

    //Primeiro teste, vamos acionar sem nada
    u_zTiLog()

    //Segundo teste, montando um texto qualquer
    cTexto += "O Terminal de Informação nasceu em 2012." + CRLF
    cTexto += "De lá para cá, foram vários artigos e conteúdos compartilhados com a comunidade." + CRLF
    cTexto += "Agradecemos sempre o carinho e o feedback recebido dos internautas." + CRLF
    cTexto += "Um grande abraço!" + CRLF
    cTexto += CRLF
    cTexto += "Dan"
    u_zTiLog(cTexto)

    //Terceiro teste, forçando um erro (update em tabela que não existe)
    cQuery := " UPDATE TABELA_AAA_BBB_CCC " + CRLF
    cQuery += " SET CAMPO_1 = 'ZZ" + Time() + "'  " + CRLF
    cQuery += " WHERE CAMPO_2 = 'F0001' " + CRLF
    If TCSqlExec(cQuery) < 0
        cTexto := "Houve uma falha no sistema!" + CRLF + CRLF
        cTexto += "Query executada:" + CRLF
        cTexto += cQuery + CRLF
        cTexto += "Mensagem de erro:" + CRLF + CRLF
        cTexto += TCSQLError() + CRLF
        u_zTiLog(cTexto)
    EndIf

    FWRestArea(aArea)
Return

/*/{Protheus.doc} zTiLog
Exemplo de tela para análise de logs com opção como Ctrl+F e número de linhas
@type user function
@author Atilio
@since 25/01/2024
@version version
@param cTextoLog, Caractere, Conteúdo textual que será demonstrado no log
@example
    u_zTiLog("beluguinha, belugão, acesse Terminal de Informação")
/*/
User Function zTiLog(cTextoLog)
    Local aArea       := FWGetArea()
    Local oDlgAux
    Local cJanTitulo := "Análise de Logs do Sistema"
    //Tamanho da janela
    Local aTamanho := FwGetDialogSize()
    Local nJanLarg := aTamanho[4] / 2
    Local nJanAltu := aTamanho[3] / 2
    //Blocos de código dos botões
    Local bBlocoCopi  := {|| fCopiar(cTextoLog)}
    Local bBlocoSalv  := {|| fSalvar(cTextoLog)}
    Local bBlocoFech  := {|| oDlgAux:DeActivate()}
    //Variáveis dos objetos de navegação de páginas
	Local cHtmlText   := ""
	Local nPort       := 0
	Local oPanelHtml
	Local oWebChannel
	Local oWebEngine
    //Parâmetros vindos
    Default cTextoLog := "Não veio nenhum texto..."

    //Cria o HTML base
	cHtmlText := fMontaHtml(cTextoLog)

    //Instancia a classe, criando uma janela
    oDlgAux := FWDialogModal():New()
    oDlgAux:SetTitle(cJanTitulo)
    oDlgAux:SetSize(nJanAltu, nJanLarg)
    oDlgAux:EnableFormBar(.T.)
    oDlgAux:CreateDialog()
    oDlgAux:CreateFormBar()
    oDlgAux:AddButton("Fechar", bBlocoFech, "Fechar", , .T., .F., .T., )
    oDlgAux:AddButton("Copiar", bBlocoCopi, "Copiar", , .T., .F., .T., )
    oDlgAux:AddButton("Salvar", bBlocoSalv, "Salvar", , .T., .F., .T., )

    //Busca o painel principal da dialog
    oPanelHtml := oDlgAux:GetPanelMain()
    
    //Prepara o conector WebSocket
    oWebChannel := TWebChannel():New()
    nPort := oWebChannel::connect()

    //Cria componente
    oWebEngine := TWebEngine():New(oPanelHtml, 0, 0, 100, 100, , nPort)
    oWebEngine:SetHtml(cHtmlText)
    oWebEngine:Align := CONTROL_ALIGN_ALLCLIENT

    //Abre a janela
    oDlgAux:Activate()

    FWRestArea(aArea)
Return

//Referência: https://stackoverflow.com/questions/1995370/adding-line-numbers-to-html-textarea
Static Function fMontaHtml(cTexto)
	Local cHtml := ""

	cHtml += '<html>' + CRLF
	cHtml += '<head>' + CRLF
    cHtml += '	<meta charset="UTF-8">' + CRLF
	cHtml += '	<script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.js"></script>' + CRLF
	cHtml += '	<script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/mode/perl/perl.min.js"></script>' + CRLF
	cHtml += '	<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.css"></link>' + CRLF
	cHtml += '	<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/theme/abbott.min.css"></link>' + CRLF
	cHtml += '' + CRLF
	cHtml += '	<style>' + CRLF
	cHtml += '	.CodeMirror {' + CRLF
	cHtml += '		width: 100%;' + CRLF
	cHtml += '		height: 90%;' + CRLF
	cHtml += '		border: 1px #000 solid;' + CRLF
	cHtml += '		border-radius: 8px;' + CRLF
	cHtml += '	}' + CRLF
	cHtml += '	</style>' + CRLF
	cHtml += '</head>' + CRLF
	cHtml += '<body>' + CRLF
	cHtml += '' + CRLF
	cHtml += '	<textarea id="code" name="code" wrap="hard" readonly>' + cTexto + '</textarea>' + CRLF
	cHtml += '  <p><font color="red">Observação:</font> Para pesquisar, clique em alguma parte do texto e pressione <strong>Ctrl+F</strong></p>' + CRLF
	cHtml += '' + CRLF
	cHtml += '	<script>' + CRLF
	cHtml += '		var editor = CodeMirror.fromTextArea(document.getElementById("code"), {' + CRLF
	cHtml += '			lineNumbers: true,' + CRLF
    cHtml += '			lineWrapping: true,' + CRLF
	cHtml += '			mode: "text",' + CRLF
	cHtml += '			theme: "",' + CRLF
	cHtml += '		});' + CRLF
	cHtml += '	</script>' + CRLF
	cHtml += '</body>' + CRLF
	cHtml += '</html>' + CRLF
Return cHtml

Static Function fSalvar(cTexto)
    Local cTipArq := "Arquivos texto (*.txt) | Arquivos de log (*.log)"
    Local cTitulo := "Gravação de arquivo"
    Local cDirIni := GetTempPath()
    Local lSalvar := .T.
    Local cArqSel := ""

    //Aciona a tela para gravar o arquivo
    cArqSel := tFileDialog(;
        cTipArq,;  // Filtragem de tipos de arquivos que serão selecionados
        cTitulo,;  // Título da Janela para seleção dos arquivos
        ,;         // Compatibilidade
        cDirIni,;  // Diretório inicial da busca de arquivos
        lSalvar,;  // Se for .T., será uma Save Dialog, senão será Open Dialog
        ;          // Se não passar parâmetro, irá pegar apenas 1 arquivo; Se for informado GETF_MULTISELECT será possível pegar mais de 1 arquivo; Se for informado GETF_RETDIRECTORY será possível selecionar o diretório
    )

    //Efetua a gravação do arquivo
    If ! Empty(cArqSel)
        MemoWrite(cArqSel, cTexto)
    EndIf
Return

Static Function fCopiar(cTexto)
    //Copia o texto para a área de transferência em memória (similar a selecionar tudo e apertar Ctrl+C)
    CopyToClipBoard(cTexto)
    FWAlertSuccess("Texto copiado para área de transferência, agora basta você usar o atalho Ctrl+V para colar onde você deseja.", "Sucesso")
Return

Bom pessoal, por hoje é só.

 

Abraços e até a próxima.

Dan (Daniel Atilio)
Cristão de ramificação protestante. Especialista em Engenharia de Software pela FIB, graduado em Banco de Dados pela FATEC Bauru e técnico em informática pelo CTI da Unesp. Entusiasta de soluções Open Source e blogueiro nas horas vagas. Autor e mantenedor do portal Terminal de Informação.

Deixe uma resposta

Terminal de Informação