Numero 05 del 2021
Titolo: Gli script di Jaws 12. La ricerca rapida di stringhe predeterminate.
Autore: Abramo Volpato.
Articolo:
Gli script di Jaws 12. La ricerca rapida di stringhe predeterminate.
Di Abramo Volpato.
Prima parte.
12.1. Lo strumento di ricerca.
Proseguendo ad esaminare i modi per far lavorare Jaws al nostro posto, dedicheremo questo capitolo alla costruzione di un sistema che ci consenta di cercare rapidamente delle stringhe testuali appositamente predisposte, che chiameremo anche "Elementi di ricerca". Ci serviremo di un vero e proprio strumento, che scorrerà per noi avanti ed indietro i documenti, fermandosi quando troverà quel che cerchiamo.
Rispetto alla classica ricerca, che si attiva digitando di volta in volta le stringhe da trovare, il nostro sistema ci consentirà di limitarci a premere delle combinazioni tasti. Sarà possibile sia cercare le singole stringhe, eseguendo da uno a nove script in serie, sia effettuare una ricerca di tutte le stringhe assieme, ed il cursore si fermerà in quel caso alla prima occorrenza di una qualsiasi stringa nell'elenco.
Potremo Inoltre usare ciascun gruppo di stringhe in tutti i file con una certa estensione, non sulla base del singolo applicativo, così come sono di solito gli script. Questo ci consentirà, quindi, di poter agire sui comandi di ricerca di una stessa stringa, relativa ad esempio al contenuto dei file ".TXT", sia che li si apra con il Blocco Note, sia che ci si trovi in Microsoft Word o Wordpad.
Forse, a sentirla così, l'utilità del sistema può non apparire così evidente. Come al solito, potremo essere più chiari quando costruiremo gli script e le funzioni necessarie, in questo e nei prossimi capitoli. Intanto, procediamo con la consueta attività iniziale del nostro lavoro.
Esercizio 12.1.1. Aggiornare il file Personale delle Costanti.
ELEMENTO = "Elemento", ; termine omonimo
MACRO = "Macro", ; termine omonimo
SCRIPTS = "Scripts", ; termine omonimo
ARCHIVIO = "Archivio", ; termine omonimo
TASTI = "Tasti", ; termine omonimo
ELABORA = "ELABORA", ; termine omonimo
TIPO = "Tipo", ; termine omonimo
CAMPO = "Campo", ; termine omonimo
UGUALE = "=", ; carattere omonimo
VOCI = "Voci", ; termine omonimo
NUMERICO = "Numerico", ; termine omonimo
INFO = "Info", ; termine omonimo
QUARTA = 4, ; valore per la posizione omonima
MULTIPLE = "Multiple", ; termine omonimo
CONFERMA = "Conferma", ; termine omonimo
CHIAMA ="Chiama", ; termine omonimo
_E = "e", ; carattere omonimo
_I = "i", ; carattere omonimo
RN ="\r\n", ; Caratteri di ritorno a capo standard, codici Ascii 13 e 10
SPV = "[!!]", ; separatore delle voci in una stringa
INGRESSO_CAMPO = "Boink2", ; suono di ingresso in un campo di editazione
USCITA_CAMPO = "Boink1", ; suono di uscita da un campo di editazione
VIRGOLA_SPAZIO =", ", ; carattere omonimo seguito da uno spazio
UNO = "1", ; cifra omonima in forma testuale
RITARDA = 4, ; decimi di secondi di attesa dopo l'emissione di un suono
CATTURA = 1, ; valore per cattura tasti di attivazione
AGGIUNGE = "Aggiunge", ; termine omonimo
AVANTI = 1, ; valore per indicare un avanzamento
RICERCA_INTERNA = "&", ; carattere che porta a cercare un elemento all'interno delle righe
INIZIO = 3, ; valore per Inizio di un elemento
INTERNO = 4, ; valore per tipo di ricerca
COLONNA = "Colonna", ; termine omonimo
ARRIVO = "Click1", ; avviso di fine ricerca o spostamento
INDIETRO = 2, ; valore per indicare l'arretramento
SCORRE_RIGHE = "ScorreRighe", ; nome della funzione omologa
MAX_RICERCA = 3000, ; massimo di millesimi di secondo per la durata delle ricerche
ESC = "Escape", ; termine esteso inglese
MAX_RIGHE = 10, ; numero massimo di righe consecutive uguali
COMMENTO = "Commento", ; termine omonimo
PUNTO_VIRGOLA = ";", ; carattere omonimo
SINGOLO = "Singolo", ; termine omonimo
ESEGUE = "Esegue", ; termine omonimo
MUOVE = "Muove", ; termine omonimo
METTE = "Mette", ; termine omonimo
Esercizio 12.1.2. Aggiornare il file Personale delle Variabili Globali.
String gsCategoria, ; ultima categoria specificata come parametro
Int gnTipo, ; tipologia di procedura
Int gnMaxVoci, ; numero massimo di voci da elaborare per la procedura
Int gnNumerico, ; determina la presenza di un prefisso numerico davanti alle voci di scelta
String gsOggetto, ; oggetto a cui si rivolge l'azione
int gnMultiple, ; indicatore di immissione testo su più righe
Int gnConferma, ; attivazione della conferma all'uscita dalla procedura
String gsChiave, ; chiave del dato attivo
String gsAttiva, ; voce selezionata nella schermata principale
Int gnTotali, ; numero degli elementi in un elenco
String gsElenco, ; elenco degli elementi da ricercare
Int gnSalta, ; indica il salto della fase di scelta voce
Int gnStato, ; stato di attivazione della sintesi
Int gnMaxCampi, ; numero complessivo delle voci nella procedura
Int gnFerma, ; indica di interrompere la funzione corrente per richiamarla in seguito
Int gnRilevamento, ; indicatore della modalità di lettura della posizione
Int gnPrimo, ; indicatore di inizio
Int gnValore, ; valore temporaneo globale
Int gnProgrammato, ; indicatore dell'avvenuta programmazione di un avvio di funzione
Int gnVerso, ; indicatore della direzione di un movimento
String gsRiga, ; testo della riga corrente
String gsPrecedente, ; contenuto testuale precedente
Int gnRipeti, ; numero di ripetizioni
Esercizio 12.1.3. Aggiornare il file Personale dei Messaggi.
; voci per scelta della tipologia delle procedure guidate
@lstTipoGuidata
Cerca nel documento, attivando script con suffisso numerico, e con doppia opzione successivo o precedente.
Scrive nel documento corrente, attivando script con suffisso numerico.
Esegue nell'applicazione corrente, attivando script con suffisso numerico.
@@
;Titolo per scelta del tipo di procedura guidata
@msgTipoGuidata
Scegliere il tipo di procedura guidata
@@
; elenco dei tasti consentiti per il campo Azioni degli script a gestione personale
@lstArchivioTasti
F1|F2|F3|F4|F5|F6|F7|F8|F9|F10|F11|F12|Alt|Control|Shift|Windows|Enter
@@
; elenco di cifre da 1 a 9
@lstCifre1_9
1|2|3|4|5|6|7|8|9
@@
; prefisso per titolo di scelta dei campi nelle procedure guidate
@msgCampiGuidate
Scegliere quanti campi prevede la procedura di
@@
; mancata scrittura sui file configurazione
@hlpNoScriveJCF
Impossibile scrivere sul file %1.JCF.
@@
; titoli per le finestre di dialogo nelle procedure guidate
@lstTitoliGuidate
Selezionare l'elemento da elaborare, e Cliccare sull'azione da compiere|Ok. avvia ricerca
Selezionare la %1 da elaborare, e cliccare sull'azione da compiere|Ok. inserisce Macro
Selezionare lo script da elaborare, e cliccare sull'azione da compiere|Esegue script. Ok, oppure Alt+O
Modifica i Tasti per attivare %1|Campo successivo. Ok, oppure Alt+O
Modifica il Sommario di %1|Campo successivo. Ok, oppure Alt+O
Modifica le Azioni da compiere tramite %1|Campo successivo. Ok, oppure Alt+O
Seleziona l'ambito in cui %1 deve agire|Conferma scelta. Ok, oppure Alt+O
@@
; seconda parte delle informazioni da proporre nelle fasi di inserimento o modifica testo
@lstInfoGuidate
%1re l'elemento in posizione %2.
%1re La Macro con il numero %2.
%1re il comando per lo script %2.
@@
; elenco prefissi funzioni per conclusione delle procedure guidate
@lstChiamaGuidate
Muove
Mette
Esegue
Cattura
@@
; elenco pulsanti per le procedure guidate di ricerca e scrittura nel documento corrente
@lstPulsantiGuidate1
Pulsante1=&modifica
Pulsante2=Agg&iunge||8
Pulsante3=e&limina
Pulsante4=sposta &giù|1|8
Pulsante5=sposta &su|2
@@
; elenco pulsanti per la prima schermata dell'elaborazione su più campi
@lstPulsantiGuidata2
Pulsante1=&modifica nome
Pulsante2=Agg&iunge||98
Pulsante3=&Duplica dall'elenco
Pulsante4=e&limina
Pulsante5=Campo s&uccessivo
@@
; elenco pulsanti per l'ultima schermata nella elaborazione su più campi
@lstPulsantiGuidata4
Pulsante1=Campo p&recedente
Pulsante2=&Torna all'inizio
@@
; elenco pulsanti per le schermate dalla seconda alla penultima nella elaborazione su più campi
@lstPulsantiGuidata3
Pulsante1=&modifica
Pulsante2=Campo s&uccessivo
Pulsante3=Campo p&recedente
Pulsante4=&Torna all'inizio
@@
; due termini separati dal carattere Controbarra
@msg2Controbarra
%1\%2
@@
; elenco tipi di suffisso
@lstTipiDato
estensione|estensione|applicazione
@@
; assenza di elementi del tipo elaborato
@ttlNoElementi
Nessun%1 %2 per l'%3 %4
@@
; prefisso per voce a righe multiple
@msgRigheMultiple
Control+Invio nuova riga.
@@
; base per messaggio nella finestra d'immissione testo
@msgMettiTesto
%1 Invio conferma, Esc annulla.
@@
; titolo mancata modifica di una voce
@ttlNoModifica
Nessuna modifica effettuata.
@@
; titolo per dato già presente
@ttlPresenzaDato
%1 %2 già presente.
@@
; invito ad immettere un nuovo testo in un campo d'inserimento
@msgAggiornaTesto
Modificare il testo immesso.
@@
; titolo per errore sulla presenza del carattere Pipe in un testo
@ttlNoPipe
Impossibile immettere un carattere Pipe, Ascii 124.
@@
; titolo sull'archiviazione dei tasti usati nelle azioni degli script a gestione personale
@ttlArchiviaTasti
Tra le azioni immesse, non si è riconosciuto %1.
@@
; conferma dei dati immessi
@msgOkDati
Confermate i dati immessi?
@@
; elenco di prefissi per immissioni o modifica testo
@lstPrefissiTesto
l'|la |il nome dello ||il |le |
@@
; elenco di suffissi per immissioni o modifica testo
@lstSuffissiTesto
in posizione %1|numero %1|||dello script %1|compiute dallo script %1
@@
; base per dato da aggiungere o modificare
@ttlInputDato
%1re %2%3 %4.
@@
; errore personalizzabile sui dati
@hlpErroreDato
Impossibile %1re il dato richiesto.
@@
; spostamento all'inizio del documento aperto
@hlpInizioFile
Inizio del documento.
@@
; spostamento all'inizio del documento aperto - versione corta
@hlpInizioFile_corto
Inizio.
@@
; pressione di Escape per interrompere
@hlpPremiEsc
Premere Escape per interrompere...
@@
; percentuale
@msgPercento
%1 percento
@@
; ricerca elementi interrotta
@msgStopRicerca
Ricerca interrotta
@@
; estensione del documento corrente non rilevata
@hlpNoEst
Nessuna estensione rilevata nel documento corrente.
@@
; estensione del documento corrente non rilevata - versione corta
@hlpNoEst_corto
Nessuna estensione.
@@
12.2. Gli archivi di configurazione.
Essendo tutto il capitolo dedicato ad un'unica procedura, abbiamo suddiviso le funzioni che la compongono nei blocchi di quelle che sono chiamate dal principale elemento di codice. Così, il primo di questi riguarda la creazione degli archivi dove andremo a registrare i dati necessari, non solo relativi alla procedura trattata in questo capitolo, ma pure a quelle di cui tratteremo da qui in avanti.
Si è preferito far generare tali archivi tramite degli script, nonostante siano in un normale file di testo, per una serie di motivi:
- Se ne può aggiornare facilmente il contenuto di base, secondo le personali preferenze.
- Saranno sempre collocati nella giusta cartella.
- Se fossero per errore cancellati, alla prima chiamata essi saranno ripristinati alla loro versione predefinita.
- Per quanto al punto precedente, nel caso di qualche modifica manuale al contenuto degli archivi che generasse degli errori, sarà quindi sufficiente cancellarli per riportarli al formato iniziale.
Gran parte dei dati trascritti negli archivi di configurazione sono stati impostati tramite delle assegnazioni nei file personali dei Messaggi, che così possono essere facilmente aggiornati e modificati. Per eventuali altre procedure, non previste da queste pagine, il sistema consente comunque di poterle implementare, proponendo delle schermate in cui scegliere i valori necessari al loro funzionamento.
Anche in questo caso, come nel capitolo scorso, le funzioni saranno predisposte per i compiti attuali e futuri. Così, dopo aver accennato degli script a gestione personale, qui inizieremo ad usare i termini "Elemento", e "Macro", che corrispondono ad altrettante categorie di procedura.
Il primo dei due termini indica proprio l'argomento del capitolo, dove "elemento di ricerca" è come detto il nome dato alle stringhe di testo predeterminate. Il secondo termine, "Macro", l'abbiamo già incontrato in particolare nel decimo capitolo, come parte centrale del nome di una coppia di speciali script, e di esso tratteremo nel dettaglio più avanti.
Esercizio 12.2.1. La funzione ConverteInBell.
FileScript. Default.JSS
Nome. ConverteInBell
Descrizione. Converte il carattere o la stringa indicati nel carattere Bell, Ascii 7.
Ritorni. Di tipo String. Il testo posto come primo parametro, eventualmente convertito.
Parametri.
1. sTesto. La stringa in cui sostituire i caratteri indicati come secondo parametro. Di tipo String.
2. sCarattere. Il carattere, o la stringa, da sostituire con il carattere Bell, Ascii 7. Di tipo String.
Note.
1. Anche questa funzione serve soltanto per semplificare la sintassi delle sostituzioni di testo.
Codice.
String Function ConverteInBell (string sTesto, string sCarattere)
Return StringReplaceSubstrings (sTesto, sCarattere, BELL); ; restituisce il testo convertito
EndFunction
Collaudo.
1. Come al solito, per tutto questo capitolo, si dovrà compilare ogni singolo script e, casomai, porre come facoltativi alcuni parametri. Dando per scontata la prima azione, in questa parte delle schede ricorderemo ogni volta solo la necessità di realizzare la seconda.
Esercizio 12.2.2. La funzione ConfigurazioneCampi.
FileScript. Default.JSS
Nome. ConfigurazioneCampi
Descrizione. Consente di impostare il file configurazione con le fasi delle procedure guidate.
Ritorni. Di tipo Int. TRUE per la creazione delle fasi, FALSE per il suo abbandono.
Novità.
1. Le nostre funzioni "ConverteInBell ()", "ScriveRecord ()" e "ScriveNumerico ()".
2. Le costanti "ELEMENTO", "MACRO", "SCRIPTS", "ARCHIVIO", "TASTI", "ELABORA", "TIPO", "CAMPO", "VOCI", "NUMERICO", "INFO", "MULTIPLE", "CONFERMA" e "CHIAMA", tutte equivalenti all'omonimo termine letterale.
3. La costante "UGUALE",, che equivale all'omonimo carattere.
4. La costante "QUARTA", che equivale al valore numerico quattro.
Fasi.
1. Una prima struttura di controllo imposta il valore del tipo di procedura sulla base del nome assegnato alla categoria della procedura stessa; qualora tale categoria non fosse riconosciuta, consente di selezionare manualmente il tipo di quest'ultima, utilizzando anche la nostra funzione "ConverteInBell ()"; se tale scelta viene annullata, il flusso sarà interrotto.
2. La seconda struttura di controllo imposta il numero di campi trattati dalla procedura, sulla base del tipo appena definito; se si devono trattare script a gestione personale, un ciclo crea l'archivio base dei nomi dei tasti validi per le azioni svolte dagli script, servendosi della nostra "ScriveNumerico ()"; anche in questo caso, qualora la categoria non avesse abbinato un numero di campi predefinito, si consente di sceglierlo da un elenco di voci numeriche e, se la fase di scelta viene annullata, il flusso s'interrompe.
3. Se nella seconda struttura è stato impostato un nome di archivio particolare, dove la procedura dovrà andare ad elaborare i dati, tale nome viene trascritto nella sezione iniziale del file di configurazione, tramite la nostra "ScriveRecord ()".
4. In ogni caso, viene effettuata una prova di scrittura, inviando all'archivio il valore del tipo di procedura rilevata; se la scrittura fallisce, ed i tasti di attivazione sono stati premuti due volte velocemente, viene pronunciato un avviso; In ogni caso,il flusso viene interrotto.
5. Da qui in avanti, viene compilato il file di configurazione, prelevando le varie assegnazioni impostate nel file personale dei Messaggi, e sulla base delle impostazioni definite nelle precedenti strutture di controllo.
Note.
1. Questa funzione, citata nella premessa, si rende necessaria per predisporre l'ambiente in cui alcune speciali procedure dovranno agire; il suo compito sarà quello di creare, o ripristinare, il file di configurazione base da dove saranno ricavati i dati necessari.
2. Essa, in quanto priva di parametri, rappresenta un buon esempio dell'utilizzo delle variabili globali, che servono soprattutto a mettere a disposizione di tutti gli elementi di codice i dati elaborati al suo interno.
Codice.
Int Function ConfigurazioneCampi ()
Var
Int iCampi, ; numero dei campi del record
Int i, ; contatore del ciclo
String sNome, ; nome dell'archivio di configurazione
String sTitoli, ; titoli delle finestre di dialogo
String sPulsanti, ; elenco delle impostazioni relative
String sInfo, ; informazioni per le fasi d'aggiunta o modifica testo
String sPrefissi, ; parti iniziali dei nomi di funzioni
Int j, ; contatore del ciclo iniziale
String sSezione, ; etichetta della sezione in cui scrivere
Int k, ; contatore del secondo ciclo
String sDato; singolo dato estratto
If gsCategoria == ELEMENTO Then; se la procedura deve scegliere elementi di ricerca,
Let gnTipo = PRIMA; imposta la scelta iniziale
ElIf gsCategoria == MACRO Then; se invece sono da scegliere i testi delle Macro,
Let gnTipo = SECONDA; imposta l'opzione alternativa
ElIf gsCategoria == SCRIPTS Then; se, ancora, sono da elaborare gli script a gestione personale,
Let gnTipo = TERZA
Else; altrimenti, se la categoria non è stata riconosciuta, consente di sceglierne il tipo
Let gnTipo = SceltaValore (ConverteInBell (lstTipoGuidata, LF), msgTipoGuidata)
If !gnTipo Then; se non si è effettuata alcuna scelta,
Return; interrompe il flusso
EndIf; fine controllo esito scelta
EndIf; fine controllo tipo procedura
If gnTipo <= SECONDA Then; se si è impostata una delle prime due scelte,
Let iCampi = 1; imposta un unico campo per il record
Let sNome = PS_FILE; imposta il nome dell'archivio di configurazione personale
Let gnMaxVoci = MAX_SEGNI; imposta le voci di scelta da 1 a 9
Let gnNumerico = TRUE; imposta la presenza di un prefisso numerico davanti alle voci
Else; altrimenti, se è infine impostato il terzo tipo di procedura,
If gsCategoria == SCRIPTS Then; se sono da elaborare gli script a gestione personale,
Let iCampi = 5; imposta i campi necessari
For i = 1 To StringSegmentCount (lstArchivioTasti, PIPE); scorre i tasti predefiniti come validi
; trascrive i tasti, predisposti nell'apposita sezione del file di configurazione personale
ScriveNumerico (PS_FILE, ARCHIVIO + TASTI, StringSegment (lstArchivioTasti, PIPE, i), TRUE)
EndFor; fine scansione tasti
Else; altrimenti, se la categoria è da definire,
Let iCampi = SceltaValore (lstCifre1_9, FormatString (ttlSelezione,msgCampiGuidate, gsOggetto, gsCategoria))
If !iCampi Then; se non è stata operata nessuna scelta,
Return; interrompe il flusso
EndIf; fine controllo scelta
EndIf; fine controllo impostazione campo
Let sNome = NULLO; resetta il dato per far impostare il file per l'applicazione
Let gnNumerico = FALSE; lascia le voci di scelta senza alcun prefisso numerico
EndIf; fine controllo tipo impostato
If sNome Then; se il nome dell'archivio di configurazione è stato impostato,
ScriveRecord (gsCategoria, ELABORA, ARCHIVIO, sNome); inizializza il file configurazione
EndIf; fine controllo nome archivio
If !ScriveNumerico (gsCategoria, ELABORA, TIPO, gnTipo) Then; se la scrittura fallisce,
If IsSameScript () Then; se i tasti di attivazione sono stati premuti due volte,
SayFormattedMessage (OT_ERROR, hlpNoScriveJCF, NULLO, gsCategoria); pronuncia l'avviso
EndIf; fine controllo doppia pressione
Return; in ogni caso, interrompe il flusso
EndIf; fine controllo scrittura
; Converte i dati in un elenco, dalla forma su più righe, per i seguenti tipi di dati:
Let sTitoli = ConverteInBell (lstTitoliGuidate, LF); titoli delle finestre di dialogo
Let sInfo = ConverteInBell (lstInfoGuidate, LF); informazioni per le fasi di immissione o modifica testo
Let sPrefissi = ConverteInBell (lstChiamaGuidate, LF); prefissi dei nomi delle funzioni da chiamare
For j = 1 To iCampi; scorre il numero di campi scelto
Let sSezione = CAMPO + IntToString (j); fissa l'etichetta per la sezione dove scrivere
ScriveRecord (gsCategoria, sSezione, TITOLO, StringSegment (sTitoli, BELL, gnTipo + (j - 1)))
If gnTipo <= SECONDA Then; se si è nei primi due tipi di procedura,
Let sPulsanti = lstPulsantiGuidate1; imposta i pulsanti modifica, Aggiunge, Elimina, Sposta Su e Giù
Else; altrimenti, nel caso della elaborazione su più campi,
If j == PRIMA Then; se si è nel primo campo,
Let sPulsanti = lstPulsantiGuidata2; imposta quelli con avanti e indietro, e Duplica script
Let gnMaxVoci = MAX_VOCI; imposta fino ad un massimo di 99 voci
ElIf j == iCampi Then; se invece si è sull'ultimo,
Let sPulsanti = lstPulsantiGuidata4; imposta quelli con i pulsanti Avanti, Indietro e Torna all'inizio
Let gnMaxVoci = MAX_VOCI; imposta fino ad un massimo di 99 voci
Else; altrimenti, negli altri campi,
Let sPulsanti = lstPulsantiGuidata3; imposta la serie senza Aggiungi ed Elimina
Let gnMaxVoci = PRIMA; riduce ad una sola la voce di scelta visualizzata
EndIf; fine controllo campo
EndIf; fine controllo tipo
Let sPulsanti = ConverteInBell (sPulsanti, LF); converte l'elenco esteso in voci
For k = 1 To StringSegmentCount (sPulsanti, BELL); scorre i dati rilevati
Let sDato = StringSegment (sPulsanti, BELL, k); estrae la prima coppia di chiavi e dati
; utilizza la prima parte fino all'Uguale come chiave, ed il resto della stringa come suo contenuto
ScriveRecord (gsCategoria, sSezione, StringSegment (sDato, UGUALE, PRIMA), StringSegment (sDato, UGUALE, SECONDA))
EndFor; fine scansione pulsanti
ScriveNumerico (gsCategoria, sSezione, VOCI, gnMaxVoci); trascrive le voci massime selezionabili
; trascrive le impostazioni sulla presenza o meno di un prefisso numerico alle voci di scelta
ScriveNumerico (gsCategoria, sSezione, NUMERICO, gnNumerico)
If gsCategoria != SCRIPTS ; se non si stanno elaborando script a gestione personale,
|| j < iCampi Then; oppure, se comunque non ci si trova nell'ultimo campo,
; trascrive le informazioni per le fasi di aggiunta o modifica testo
ScriveRecord (gsCategoria, sSezione, INFO, StringSegment (sInfo, BELL, gnTipo))
Else; altrimenti,
ScriveRecord (gsCategoria, sSezione, INFO, NULLO); trascrive un dato vuoto
EndIf; fine controllo campo
If gsCategoria == MACRO ; se si stanno elaborando le macro,
|| (gsCategoria == SCRIPTS ; oppure, se sono da elaborare gli script a gestione personale,
&& j == QUARTA) Then; ma ci si trova solo nel quarto campo,
Let gnMultiple = TRUE; imposta l'immissione testo su più righe
Else; altrimenti,
Let gnMultiple = FALSE; la disattiva
EndIf; fine controllo righe multiple
; trascrive l'impostazione attiva per le righe multiple in fase di immissione testo
ScriveNumerico (gsCategoria, sSezione, MULTIPLE, gnMultiple)
If j >= SECONDA Then; se si è un campo dal secondo in poi,
Let gnConferma = TRUE; imposta la richiesta di una conferma all'abbandono
Else; altrimenti, se si è nella schermata iniziale,
Let gnConferma = FALSE; la disattiva
EndIf; fine controllo conferme
; trascrive l'impostazione attiva per la conferma all'uscita dalla fase attiva
ScriveNumerico (gsCategoria, sSezione, CONFERMA, gnConferma)
; trascrive anche i prefissi per le funzioni da chiamare a fine procedura
ScriveRecord (gsCategoria, sSezione, CHIAMA, StringSegment (sPrefissi, BELL, gnTipo + (j - 1)))
EndFor; fine scansione campi
Return TRUE; se nessun altro controllo ha interrotto il flusso, restituisce l'esito positivo
EndFunction
Esercizio 12.2.3. La funzione FileUtente.
FileScript. Default.JSS
Nome. FileUtente
Descrizione. Determina se il file specificato esista nella cartella delle Impostazioni personali.
Ritorni. Di tipo Int. TRUE, se il file specificato esiste; FALSE, se invece non è presente.
Parametri.
1. sNome. Il nome del file da controllare. Di tipo String.
Novità.
1. La funzione integrata "FileExists", (FileEsiste); Restituisce un valore positivo se esiste un file dal nome e dal percorso indicati nel suo unico parametro.
Fasi.
1. Tramite la nostra funzione "ImpostaConfigurazione ()", si aggiunge casomai l'estensione predefinita per tali tipo di file.
2. Il nome così ottenuto viene formattato assieme al risultato della funzione integrata "FileExists ()", la quale restituisce il percorso con le impostazioni per l'Utente, inserendo tra essi un carattere Controbarra.
Codice.
Int Function FileUtente (string sNome)
ImpostaConfigurazione (sNome); se non presente, aggiunge l'estensione dei file configurazione
; restituisce il risultato del controllo sull'esistenza del file specificato
Return FileExists (FormatString (msg2Controbarra, GetUserSettingsDirectory (), sNome))
EndFunction
Esercizio 12.2.4. La funzione ArchivioDati.
FileScript. Default.JSS
Nome. ArchivioDati
Descrizione. Imposta in una variabile globale il nome dell'archivio dove leggere i dati, controllando l'esistenza ed il corretto funzionamento anche dell'apposito file relativo alla procedura.
Ritorni. Di tipo Int. TRUE, nel caso di un archivio correttamente impostato; FALSE, in qualunque caso di errore.
Novità.
1. Le nostre funzioni "FileUtente ()", "ConfigurazioneCampi ()" e "LeggeNumerico ()".
Fasi.
1. Una prima struttura di controllo verifica se l'archivio di configurazione relativo alla categoria preimpostata esista, tramite la nostra funzione "FileUtente ()"; se l'archivio non c'è, viene creato grazie alla nostra "ConfigurazioneCampi ()",e l'elaborazione continua; se però questo processo di creazione genera degli errori, il flusso viene invece interrotto.
2. Una seconda breve struttura controlla, e casomai imposta, il tipo di procedura elaborata, anche tramite la citata "LeggeNumerico ()".
3. L'ultima parte della funzione si occupa di rilevare il nome dell'archivio da elaborare, sempre impostandolo in una variabile globale, prima cercando nel file configurazione, poi casomai utilizzando il nome dell'applicativo corrente.
Note.
1. Questa funzione, che finalizza il lavoro delle altre presenti in questo blocco, serve a riunire in un'unica istruzione l'esigenza di controllare se tutti i dati necessari alle procedure siano disponibili, e quindi se siano stati impostati nelle variabili globali.
2. Anche in questo caso, l'utilizzo delle variabili globali per rendere disponibili i dati consente di non servirsi di parametri per il suo funzionamento.
Codice.
Int Function ArchivioDati ()
If !FileUtente (gsCategoria) Then; se il file di configurazione per il tipo di procedura non esiste,
If !ConfigurazioneCampi () Then; se la creazione del file non riesce,
Return FALSE; restituisce un risultato nullo
EndIf; fine controllo creazione file configurazione
EndIf; fine controllo esistenza file configurazione
If !gnTipo Then; se il tipo di procedura non è stato ancora impostato,
Let gnTipo = LeggeNumerico (gsCategoria, ELABORA, TIPO); legge il dato dal file configurazione
EndIf; fine controllo tipo procedura
Let gsArchivio = LeggeRecord (gsCategoria, ELABORA, ARCHIVIO); legge il nome dell'archivio dei dati
If !gsArchivio Then; se nessun nome è stato rilevato,
Let gsArchivio = GetActiveConfiguration (); salva il nome dell'applicazione corrente
EndIf; fine controllo presenza settaggio
Return TRUE; restituisce l'esito positivo
EndFunction
12.3. I Dati registrati.
In questa corposa sezione del capitolo sono ricomprese una serie di funzioni che riconducono tutte alla ricerca, al controllo ed all'eventuale prima impostazione delle stringhe da elaborare. Il numero degli elementi di codice coinvolti è reso notevole dalla presenza di alcune funzioni chiave, sia per l'immissione materiale delle stringhe, sia per una nuova versione di quella per la richiesta di conferme, che poi saranno usate molto spesso da qui in avanti.
Proprio per questo, le funzioni trattate saranno suddivise in alcuni blocchi, che saranno illustrati tramite degli appositi titoli. Purtroppo, per realizzare un vero collaudo del codice contenuto in questa sezione, e nelle due che seguiranno, bisognerà attendere con pazienza la fine del capitolo.
12.3.1. Adattare messaggi e titoli delle finestre di dialogo.
Il primo blocco di questa sezione, composto da cinque funzioni, è finalizzato alla proposizione di un controllo che consente o meno di far proseguire il flusso. A caratterizzare però questo blocco è soprattutto l'aggiornamento della funzione che chiede la conferma delle scelte.
Nel dettaglio, tale modifica deve consentire alla funzione di essere chiamata senza influire sui dati già memorizzati dalla procedura chiamante . A questo compito è destinato il terzo elemento di questo blocco, che gestisce la conservazione dei dati preesistenti, sfruttando sia i parametri per riferimento, che trasmetteranno i valori validi solo a livello locale, sia le variabili globali, che serviranno per restituire i dati modificati provvisoriamente dalla funzione di conferma.
I primi due elementi del blocco, infine, sono dedicati alla coniugazione al plurale e singolare delle desinenze femminili e maschili dei termini, che servono a personalizzare i messaggi nelle finestre di dialogo.
Esercizio 12.3.2. La funzione PersonaFemminile.
FileScript. Default.JSS
Nome. PersonaFemminile
Descrizione. Determina quale vocale femminile restituire, sulla base del valore immesso come parametro.
Ritorni. Di tipo String. La vocale impostata sulla base del valore immesso.
Parametri.
1. iValore. Il valore che determina la vocale da restituire, sulla base della persona singolare, ponendo il numero 1, o plurale, specificando qualsiasi altro valore. Di tipo Int.
Novità.
1. La costante "_E", che include l'omonimo carattere minuscolo.
Note.
1. Questa funzione è la prima di una coppia che svolge lo stesso compito, personalizzando dei termini sulla base del valore immesso come parametro; le due opzioni previste dalla funzione sono quelle più ricorrenti, mentre le eccezioni dovranno essere trattate con modifiche più mirate.
Codice.
String Function PersonaFemminile (int iValore)
If iValore == PRIMA Then; se si deve completare un termine singolare,
Return _A; restituisce l'omonima costante
Else; altrimenti, con tutti gli altri valori, che indicano un termine plurale,
Return _E; restituisce l'omonima costante
EndIf; fine controllo valore
EndFunction
Esercizio 12.3.3. La funzione PersonaMaschile.
FileScript. Default.JSS
Nome. PersonaMaschile
Descrizione. Determina quale vocale maschile restituire, sulla base del valore immesso come parametro.
Ritorni. Di tipo String. La vocale impostata sulla base del valore immesso.
Parametri.
1. iValore. Il numero che determina la vocale da restituire: 1, per un termine singolare, o tutti gli altri, per un termine plurale. Di tipo Int.
Novità.
1. La costante "_I", che equivale all'omonimo carattere minuscolo.
Codice.
String Function PersonaMaschile (int iValore)
If iValore == PRIMA Then; se si deve completare un termine singolare,
Return _O; restituisce l'omonima costante
Else; altrimenti, con tutti gli altri valori, che indicano un termine plurale,
Return _I; restituisce l'omonima costante
EndIf; fine controllo valore
EndFunction
Esercizio 12.3.4. La funzione ScambiaTitoli.
FileScript. Default.JSS
Nome. ScambiaTitoli
Descrizione. Se si indica un primo parametro, esso viene registrato in una variabile globale riservata al titolo, salvando l'eventuale precedente contenuto in una variabile locale trasmessa per riferimento; inoltre, sarà azzerato il dato di un'altra variabile globale dedicata alle etichette dei pulsanti nelle finestre di dialogo, anche qui salvandone casomai il contenuto in una variabile locale trasmessa per riferimento. Nel caso in cui non si indichi un primo parametro, i valori delle variabili locali sono riassegnati alle rispettive variabili globali.
Ritorni. Di tipo Void. Nessuno.
Parametri.
1. sTitolo. Il testo da registrare come titolo. Di tipo String.
2. sBufferTitolo. Per Riferimento. L'eventuale precedente contenuto della variabile globale con il titolo della finestra di dialogo. Di tipo String.
3. sBufferEtichette. Per Riferimento. L'eventuale precedente contenuto della variabile globale con le etichette dei pulsanti della finestra di dialogo. Di tipo String.
Note.
1. Il motivo che costringe a cambiare il contenuto di alcune variabili globali è che tale contenuto è utilizzato da altri script, in particolare da quello che legge il titolo della finestra e dal nostro che propone l'Aiuto in linea, per pronunciare o porre nel Visualizzatore Virtuale alcune informazioni. Poiché tali informazioni cambiano se i citati script sono richiamati dalla finestra principale, oppure da una finestra di dialogo secondaria, è necessario che, alla comparsa di una nuova finestra, il contenuto delle variabili globali vada di volta in volta aggiornato.
2. Questa funzione ricorda per certi versi il sistema di memorizzazione usato per lo script "AiutoInLinea ()", come indica il prefisso "buffer" inserito prima del nome effettivo della variabile locale.
Codice.
Void Function ScambiaTitoli (string sTitolo, ; intestazione con il primo parametro,
string ByRef sBufferTitolo, string ByRef sBufferEtichette); seconda riga con gli altri due
If sTitolo Then; se il primo parametro è stato indicato,
Let sBufferTitolo = gsTitolo; salva l'eventuale titolo già registrato,
Let gsTitolo = sTitolo; e assegna alla variabile globale il parametro indicato
Let sBufferEtichette = gsEtichette ; memorizza le eventuali etichette impostate,
Let gsEtichette = NULLO; e azzera la variabile globale, per impedire la lettura dell'Aiuto in linea
Else; altrimenti, se il primo parametro non è stato indicato,
Let gsTitolo = sBufferTitolo; riassegna il titolo precedentemente salvato
Let gsEtichette = sBufferEtichette; riassegna anche le etichette casomai registrate
EndIf; fine controllo titolo
EndFunction
Esercizio 12.3.5. La versione aggiornata di ChiedeConferma ().
FileScript. Default.JSS
Nome. ChiedeConferma
Novità.
1. La nostra funzione "ScambiaTitoli ()".
Note.
1. Le prime modifiche alla precedente versione, di cui si è accennato ad inizio sezione, sono le dichiarazioni delle due variabili locali, usate per memorizzare i dati attivi, poste tra quelle delle variabili "iStato" e "iDettagli", nella seguente forma:
String sBufferTitolo, ; eventuale precedente contenuto del titolo predefinito
String sBufferEtichette, ; eventuale precedente contenuto delle etichette dei pulsanti
2. La seconda modifica riguarda la prima chiamata della nostra funzione appena realizzata, che memorizza i dati attivi, la quale va posta subito dopo la prima struttura di controllo nella seguente forma su due righe:
; memorizza gli eventuali contenuti di titolo ed etichette della finestra di dialogo
ScambiaTitoli (FormatString (msg2Spazi, sTitolo, sMessaggio), sBufferTitolo, sBufferEtichette)
3. La terza ed ultima modifica riguarda il ripristino dei dati salvati nelle variabili locali, memorizzandoli nelle corrispettive variabili globali, ponendo appena sotto la seconda chiamata della nostra funzione "ControllaSintesi ()", la seguente istruzione:
ScambiaTitoli (NULLO, sBufferTitolo, sBufferEtichette); ripristina le variabili globali
4. Come al solito, in caso di dubbi, fate riferimento alla forma modificata, che poniamo di seguito.
Codice.
Int Function ChiedeConferma (string sTitolo, string sMessaggio, ; intestazione con due parametri,
int iOpzioni, int iTasto, int iNoSuoni); seconda riga con gli altri tre
Var
Int iStato, ; attivazione della sintesi vocale
String sBufferTitolo, ; eventuale precedente contenuto del titolo predefinito
String sBufferEtichette, ; eventuale precedente contenuto delle etichette dei pulsanti
int iDettagli, ; valore esadecimale per icona e suoni
Int iScelta; valore della scelta effettuata
Let iStato = ControllaSintesi (TRUE, TRUE); riattiva la sintesi, annotandone lo stato d'attivazione
If !sTitolo ; se nessun titolo è stato specificato,
&& !sMessaggio Then; e se non lo è stato neppure un messaggio,
Let sTitolo = msgConfermaUscita; imposta un messaggio come titolo
EndIf; fine controllo titolo e messaggio
; memorizza gli eventuali contenuti di titolo ed etichette della finestra di dialogo
ScambiaTitoli (FormatString (msg2Spazi, sTitolo, sMessaggio), sBufferTitolo, sBufferEtichette)
AssegnaEsadecimali (iOpzioni, iDettagli); imposta i valori tramite l'apposita funzione
If !iTasto || iTasto == PRIMA Then; se non è stato indicato nulla, oppure il primo valore,
Let iTasto = MB_DEFBUTTON1; aggiorna come predefinito il primo pulsante nella linea dei tasti Tab
ElIf iTasto == SECONDA Then; se invece è stato indicato il secondo valore,
Let iTasto = MB_DEFBUTTON2; aggiorna come predefinito il secondo pulsante
ElIf iTasto == TERZA Then; se invece è stato indicato il terzo valore,
Let iTasto = MB_DEFBUTTON3; aggiorna come predefinito il terzo pulsante
Else; altrimenti,
Let iTasto = MB_DEFBUTTON4; aggiorna come predefinito il quarto pulsante
EndIf; fine controllo tasto predefinito
If !iNoSuoni Then; se non è stata indicata la cancellazione dei suoni,
Let iScelta = ExMessageBox (sMessaggio, sTitolo, iOpzioni|iTasto|iDettagli); propone la classica conferma
Else; altrimenti,
Let iScelta = ExMessageBox (sMessaggio, sTitolo, iOpzioni|iTasto); la propone senza icona e suoni
EndIf; fine controllo sintassi
ControllaSintesi (iStato, TRUE); ripristina, o lascia invariato, il precedente stato di attivazione della sintesi
ScambiaTitoli (NULLO, sBufferTitolo, sBufferEtichette); ripristina le variabili globali
If iScelta == IDNO Then; se si è premuto il tasto No,
Return -1; restituisce un risultato negativo
ElIf iScelta == IDCANCEL Then; se invece si è premuto Escape o Annulla,
Return FALSE; restituisce un risultato nullo
Else; altrimenti,
Return iScelta; restituisce la scelta operata
EndIf; fine controllo scelta
EndFunction
Esercizio 12.3.6. La funzione ProsegueFlusso.
FileScript. Default.JSS
Nome. ProsegueFlusso
Descrizione. Consente di proseguire o interrompere la creazione di nuovi elementi durante l'utilizzo di una procedura.
Ritorni. Di tipo Int. TRUE per confermare la prosecuzione, FALSE per interromperla.
Parametri.
1. sCategoria. Il tipo di dato da elaborare. Di tipo String.
2. sSuffisso. Ultimo termine dello script chiamante. Di tipo String.
Novità.
1. Le nostre funzioni "PersonaFemminile ()" e "PersonaMaschile ()".
Fasi.
1. La prima struttura di controllo imposta la desinenza dei termini nel titolo e nel messaggio della finestra di dialogo, grazie alla nostra funzione "PersonaFemminile ()" e sulla base della categoria della procedura attiva.
2. Una seconda struttura imposta invece un suffisso per il messaggio, solo nel caso che il tipo di procedura sia il terzo.
3. Dopo aver impostato il titolo, un'ultima struttura controlla ancora l'impostazione di una desinenza, tramite la citata funzione "PersonaMaschile ()".
4. Viene infine restituito il risultato della funzione con la richiesta di conferma, il cui messaggio viene direttamente formattato come parametro della funzione stessa.
Codice.
Int Function ProsegueFlusso (string sCategoria, string sSuffisso)
Var
String sFinale, ; lettera conclusiva di un termine
String sDato, ; tipologia di suffisso
String sTitolo; titolo della finestra di dialogo
If sCategoria == MACRO Then; se si stanno elaborando delle macro,
Let sFinale = PersonaFemminile (PRIMA); imposta la desinenza singolare femminile
ElIf sCategoria == SCRIPTS Then; se invece si stanno elaborando gli script a gestione personale,
Let sFinale = PersonaMaschile (PRIMA); imposta la desinenza singolare maschile
EndIf; fine controllo categoria
If gnTipo == TERZA Then; se si stanno elaborando procedure su più campi,
Let sSuffisso = GetActiveConfiguration (); imposta come suffisso il nome dell'applicazione corrente
EndIf; fine controllo tipo procedura
Let sDato = StringSegment (lstTipiDato, PIPE, gnTipo); estrae il tipo di suffisso,
Let sTitolo = FormatString (ttlNoElementi, sFinale, sCategoria, sDato, sSuffisso); e crea il titolo
If sCategoria == ELEMENTO Then; se si stanno elaborando gli elementi di ricerca,
Let sFinale = PersonaMaschile (PRIMA); la mette al maschile
EndIf; fine controllo prefisso
Return ChiedeConferma (sTitolo, FormatString (msgImmissione, sFinale)); restituisce la scelta
EndFunction
12.3.7. Due elementi autonomi.
Le prossime due funzioni sono due elementi a sé stanti, che hanno in comune solo il largo uso delle variabili globali.
La prima delle due serve solo a determinare quale termine sarà formattato nel messaggio delle finestre di dialogo, sulla base del tipo di procedura attiva.
La seconda si occupa invece di creare degli elenchi di voci, suddivise tramite i caratteri indicati o un separatore predefinito. Tali elenchi possono essere di tutte le voci in memoria, parziali o composti di un'unica voce, sulla base dei parametri indicati e dei dati impostati per la procedura attiva.
Esercizio 12.3.8. La funzione ComponeTermine.
FileScript. Default.JSS
Nome. ComponeTermine
Descrizione. Controlla quale termine da formattare andrà restituito, sulla base del tipo di procedura attiva.
Ritorni. Di tipo String. Il termine da formattare nelle finestre di dialogo.
Note.
1. I dati restituiti, sempre sulla base del tipo di procedura attiva, provengono entrambi da delle variabili globali, il cui significato preciso sarà illustrato solo più avanti.
Codice.
String Function ComponeTermine ()
If gnTipo <= SECONDA Then; se ci si trova nei primi due tipi di procedura,
Return gsChiave; restituisce il valore testuale della chiave come termine da formattare
Else; altrimenti, nelle procedure del terzo tipo,
Return gsAttiva; restituisce la voce corrente del campo principale
EndIf; fine controllo termine da formattare
EndFunction
Esercizio 12.3.9. La funzione CreaElenco.
FileScript. Default.JSS
Nome. CreaElenco
Descrizione. Crea un elenco di elementi da utilizzare in ricerche e confronti.
Ritorni. Di tipo String. L'elenco degli elementi da elaborare.
Parametri.
1. sArchivio. Il nome, senza estensione, dell'archivio da elaborare. Di tipo String.
2. sSezione. La sezione dell'archivio in cui operare. Di tipo String.
3. iCampo. L'eventuale numero del campo di cui estrarre i dati; se non specificato, viene usato quello generato dalla nostra apposita funzione. Di tipo Int. Parametro Opzionale.
4. sSeparatore. L'eventuale separatore degli elementi nell'elenco; se non specificato, viene usato il carattere Bell, Asci 7. Di tipo String. Parametro Opzionale.
Fasi.
1. Le prime due strutture controllano che un dato sia stato specificato come terzo o quarto parametro, il numero di campo o il carattere separatore, altrimenti ne assegnano il valore predefinito.
2. Se ci si trova in uno dei primi due tipi di procedura, si tenta di leggere la posizione dell'ultimo dato elaborato, per considerarla come numero massimo di voci utilizzabili tra quelle esistenti.
3. Se nessun precedente dato è registrato, o ci si trova in una procedura a più campi, il numero delle voci da utilizzare coincide con quello totale delle voci presenti nell'elenco.
4. Un ciclo scorre le voci registrate, aggiungendo tra di esse solo quelle necessarie e restituendo poi la nuova forma dell'elenco, nella quale è stato casomai sostituito il carattere di separazione tra le voci.
Note.
1. In pratica, la funzione serve soprattutto quando, tra gli elementi di ricerca registrati per l'estensione del documento corrente, ne siano registrati ad esempio tutti i nove possibili, ma si vuole limitare la ricerca solo ai primi tra essi.
Codice.
String Function CreaElenco (string sArchivio, string sSezione, int iCampo, string sSeparatore)
Var
Int iValide, ; numero delle voci da inserire nell'elenco
Int i, ; contatore del ciclo
String sRecord, ; dati registrati
String sChiave, ; chiave del record
String sVoci; elenco da restituire
If !iCampo Then; se nessun numero di campo è stato specificato,
Let iCampo = CampoGlobale (); viene usato il valore nella variabile globale, o il numero 1
EndIf; fine controllo campo
If !sSeparatore Then; se nessun separatore delle voci di elenco è stato specificato,
Let sSeparatore = BELL; viene usato il carattere Bell, Ascii 7
EndIf; fine controllo separatore
If gnTipo <= SECONDA Then; se si è nei primi due tipi di elaborazione,
Let iValide = StringToInt (LeggeRecord (sArchivio, sSezione, ZERO)); legge il dato sull'ultima impostazione
If !iValide ; se il valore non è stato rilevato,
&& gnTotali >= CICLO_VOCI Then; e le voci sono maggiori o uguali al valore predefinito,
Let iValide = CICLO_VOCI; lo imposta
EndIf; fine primo controllo voci
EndIf; fine controllo tipo elaborazione
If !iValide Then; se il valore non è ancora stato definito,
Let iValide = gnTotali; imposta il numero totale delle voci registrate
EndIf; fine controllo impostazione valore
For i = 1 To iValide; scorre il numero di voci impostato
Let sChiave = StringSegment (gsElenco, PIPE, i); estrae la singola chiave
Let sRecord = LeggeRecord (sArchivio, sSezione, sChiave); rileva l'intero record di dati
; aggiunge all'elenco delle voci da comporre il dato riferito al campo attivo
Let sVoci = CambiaCampo (sVoci, StringSegment (sRecord, PIPE, iCampo), ULTIMA, sSeparatore)
EndFor; fine scansione chiavi
Return sVoci; restituisce il nuovo elenco con i dati
EndFunction
Per ulteriori spiegazioni, scrivere a: Abramo Volpato, oppure, a: Nunziante Esposito