Implementazione di una
interfaccia grafica (GUI) per la gestione di una rete di illuminazione pubblica. L’applicazione, legge da un database esterno i dati della rete di illuminazione e li presenta all’utente. Questi dati comprendono le coordinate
GPS, le caratteristiche tecniche e l’indirizzo seriale di ciascun lampione. Mediante questi dati la rete di illuminazione viene rappresentata su una mappa
topografica e sottoforma di lista ordinata.
L’operatore ha quindi a disposizione una serie di strumenti e di criteri
per la seleziare i lampioni e per inviare determinati comandi da remoto.
Progetto, realizzazione e caratterizzazione dell'elettronica di acquisizione ...
Public Light Manager - Una GUI per la gestione remota di un impianto di illuminazione pubblica
1. `
Universita Politecnica delle Marche
`
Facolta di Ingegneria
Corso di
Microelettronica
Public Lighting Manager
Una GUI per la gestione di impianti di
illuminazione pubblica
Relatore Studente
Prof. Claudio Turchetti Gianluca Ritrovati
Correlatore matr: 221143
Prof. Giorgio Biagetti
Anno Accademico 2011/2012
2. `
Universita Politecnica delle Marche
`
Facolta di Ingegneria
Corso di
Microelettronica
Public Lighting Manager
Una GUI per la gestione di impianti di
illuminazione pubblica
Relatore Studente
Prof. Claudio Turchetti Gianluca Ritrovati
Correlatore matr: 221143
Prof. Giorgio Biagetti
Anno Accademico 2011/2012
3. Abstract
In questa tesina viene relazionato il lavoro di implementazione di una
interfaccia grafica (GUI) per la gestione di una rete di illuminazione pub-
blica. L’applicazione, legge da un database esterno i dati della rete di illu-
minazione e li presenta all’utente. Questi dati comprendono le coordinate
GPS, le caratteristiche tecniche e l’indirizzo seriale di ciascun lampione. Me-
diante questi dati la rete di illuminazione viene rappresentata su una mappa
topografica e sottoforma di lista ordinata.
L’operatore ha quindi a disposizione una serie di strumenti e di criteri
per la seleziare i lampioni e per inviare determinati comandi da remoto.
1
6. Capitolo 1
Introduzione
In questo capitolo si descrive il contesto teconologico nel quale il progetto
` stato ideato. Vengono fissati gli obiettivi da raggiungere ed illustrate le
e
motivazioni che hanno portato alla scelta di determinate tecnologie.
Viene infine descritta la struttura della tesina.
1.1 Scenario
Nell’ambito di politiche di risparmio energetico sempre pi` stringenti [5],
u
il settore dell’illuminazione sta vivendo un profondo moto di rinnovamento.
Sia in campo domestico, che in campo industriale infatti, le tecnologie ener-
geticamente meno efficienti, vengono progressivamente sostituite con nuovi
sistemi con alto rendimento e minor consumo.
Il settore pubblico non fa eccezione, basti pensare che la voce di spesa
maggiore per un bilancio comunale, ` quella relativa alla pubblica illumi-
e
nazione, sia per quanto riguarda il consumo energetico e sia per i costi di
gestione e manutenzione.
Le soluzioni che permettono un risparmio economico, implicano quindi
sia l’uso di dispositivi di illuminazione pi` efficienti, come ad esempio proiet-
u
tori a tecnologia LED e sia una gestione telecontrollata di questi dispositivi,
capace di regolare in tempo reale i flussi luminosi a seconda delle esigenze e
della variabilit` delle condizioni di luce naturale.
a
Da un punto di vista tecnico quindi, ` facile prevedere l’uso sempre mag-
e
giore di elettronica di controllo ed in particolare, l’uso di protocolli wireless
come lo ZigBee [1] [8]. Lo sviluppo futuro sar` quello di creare una rete
a
4
7. 1.2 Obiettivi 5
Fig. 1.1: Una rete di lampioni
intelligente di illuminazione, la cui gestione ` affidata ad un computer cen-
e
trale, dal quale poter avviare opportuni programmi di illuminamento o su
cui ricevere tutte le informazioni sullo stato e sul consumo dei proiettori.
1.2 Obiettivi
Ipotizzando uno scenario come quello descritto precedentemente, il la-
voro svolto in questo progetto, ` stato quello di sviluppare una interfac-
e
cia grafica (Graphical User Interface), per la gestione remota della rete di
illuminazione pubblica.
L’applicazione deve poter leggere da un database esterno i dati relativi
ai singoli lampioni della rete. Questi dati sono:
• l’identificativo (ID) dell’apparato illuminante;
• le coordinate geografiche del lampione, espresse come latitudine e lon-
gitudine;
• il nome della via dove il lampione ` situato;
e
• il gruppo (circoscrizione, quartiere, ecc.) al quale il lampione appar-
tiene;
• il tipo di supporto (su palo, a sospensione, a muro ecc.) e la data
ultima di sostituzione;
8. 1.3 Scelte tecnologiche 6
• il tipo di lampada (a LED, ai vapori di sodio, alogena ecc.) e la data
ultima di sostituzione;
• il nome dell’operatore che ha effettuato l’installazione o l’ultimo inter-
vento;
• l’indirizzo seriale per l’invio dei comandi.
L’applicazione deve prevedere la possibilit` modificare e di integrare,
a
successivamente, tutte le voci del database a seconda delle necessit`.
a
La rete di illuminazione deve essere rappresentata su una mappa, secondo
le coordinate di ciascun elemento.
Inoltre l’operatore deve poter selezionare sulla mappa i singoli lampioni,
sui quali poter effettuare le operazioni del caso.
L’applicazione deve prevedere anche una forma di rappresentazione tabel-
lare, con un pannello filtri che permetta la selezione per ubicazione, per
gruppo, per lampada montata e per operatore tecnico.
Al momento della stesura del progetto non ` stato ancora definito nello
e
specifico l’hardware di comunicazione dei lampioni, pertanto le operazioni
effettuabili su questi dispositivi sono limitati ai comandi di accensione e
spegnimento. Per lo stesso motivo non sono implementati gli algoritmi per
il trattamento dei segnali di comunicazione con i dispositivi, ma i comandi
si riducono alla semplice scrittura su un file di log ( log file.txt).
1.3 Scelte tecnologiche
Il progetto, che d’ora in avanti chiameremo “Public Lighting Manager” (o
abbreviato P.L.M.), ` stato scritto in linguaggio C++, utilizzando il frame-
e
work Qt versione 4.7 [2]. Si tratta di una libreria di propriet` della Nokia,
a
distribuita gratuitamente, appositamente studiata per la realizzazione in-
terfacce grafiche, con un approccio particolarmente orientato agli oggetti.
Questo framework ` multipiatatforma, quindi permette il porting dell’appli-
e
cazione su diversi sistemi operativi (Linux, Windows e Mac) e su sistemi em-
beded, come PDA e smartphones. Inoltre, Qt ingloba una serie di API (Ap-
plication Programming Interface) di generica utilit`, che ci hanno agevolato
a
nel creare le funzioni per l’accesso dell’applicazione al database SQL, nella
programmazione di rete e nella lettura/scrittura in formato XML.
9. 1.4 Struttura della tesina 7
Per lo storage dei dati abbiamo utilizzato un database di tipo MySql [3].
Si tratta di un database open source, ormai diffusissimo grazie alle sue ottime
prestazioni, alla sua elevata affidabilit` e alla facilit` d’utilizzo. E’ anch’esso
a a
multipiattaforma ed ` ben supportato da Qt.
e
Per la visualizzazione della mappa ` stato utilizzato il servizio Open-
e
StreetMap [6]. Si tratta di un sistema partecipativo, simile a Wikipedia,
per la condivisione di dati cartografici da apparati GPS. Rispetto al noto
servizio Google Maps le mappe OSM possono essere utilizzate liberamente (e
gratuitamente) all’interno delle applicazioni, a patto che se ne citi la fonte.
La natura collaborativa del progetto OSM fa si che il materiale mappale sia
sempre aggiornato e corretto. In presenza di nuove urbanizzazioni, ad es-
empio, ` sufficiente aggiornare i dati caricando i nuovi tracciati con l’ausilio
e
di un normale dispositivo GPS.
1.4 Struttura della tesina
• Capitolo 2: Background. In questo capitolo viene presentata una
panoramica sulle tecnologie adottate che sono alla base del progetto e
sulle motivazioni che ne hanno determinato la scelta.
• Capitolo 3: Il Public Lighting Manager. In questo capitolo illustreremo
il funzionamento dell’applicazione dal punto di vista dell’utilizzatore
finale.
• Capitolo 4: Implementazione dell’applicazione. Viene presentata la
struttura del progetto, sotto l’aspetto dell’implementazione del codice.
Segue una panoramica sulle classi e le funzioni principali.
• Capitolo 5: Conclusioni e sviluppi futuri. Si presentano i risultati
dei test dell’interfaccia e le problematiche riscontrate. Si analizzano
inoltre i possibili sviluppi dell’interfaccia.
10. Capitolo 2
Background
2.1 La libreria Qt
Il framework Qt nasce da un progetto di Haavard Nord e Eirik Chambe-
Eng (fondatori della Trolltech) nell’ambito della realizzazione di un ambi-
ente per lo sviluppo di interfacce grafiche in C++ [10]. Mentre erano im-
pegnati in questo progetto, ai due venne l’idea di rendere quel framework
multipiattaforma, garantendo la presenza delle stesse API sotto ogni sistema
operativo. Nel 1995 venne pubblicata la prima versione del framework Qt.
Nella programmazione di interfacce grafiche si richiede una buona effi-
cienza a tempo di esecuzione ed un elevato grado di flessibilit`. Per soddis-
a
fare questi requisiti che Qt combina alla velocit` del C++ la flessibilit` del
a a
suo modello ad oggetti.
Nello specifico, Qt aggiunge le seguenti potenzialit` al C++:
a
• un potente meccanismo di comunicazione tra oggetti chiamato Signals
and Slots;
• un potente sistema di eventi e filtraggio degli eventi;
• l’internazionalizzazione delle applicazioni;
• la possibilit` di richiedere all’oggetto le sue propriet` dinamicamente;
a a
• un sistema di timer;
• una gerarchia di oggetti, dove QObject n´ ` la radice;
ee
• un sistema di puntatori;
8
11. 2.1 La libreria Qt 9
• un cast dinamico che opera attraverso le librerie.
Molte di queste caratteristiche vengono implementate con le tecniche
standard del C++, mentre altre, come la comunicazione Signals and Slots
e il sistema dinamico delle propriet`, richiede il Meta-Object System imple-
a
mentato da Qt attraverso il Meta-Object Compiler (MOC).
Le classi che stanno alla base del modello ad oggetti di Qt sono:
• QMetaClassInfo: contiene le informazioni su una classe
• QMetaEnum: contiene i meta dati dei tipi enumerativi
• QMetaMethod: contiene i meta dati sulle funzioni membro
• QMetaObject: contiene meta informazioni sugli oggetti Qt
• QMetaProperty: contiene meta data che riguardano le propriet`
a
• QMetaType: gestisce i nomi dei tipi nel Meta-Object System
• QObject: la radice della gerarchia di oggetti Qt
• QObjectCleanupHandler: gestisce il ciclo di vita degli oggetti
• QPointer: classe che implementa i puntatori agli oggetti
• QSignalMapper: gestisce i segnali dai sender identificati
• QVariant: questa classe agisce come l’unione dei principali tipi degli
oggetti Qt
Un oggetto Qt valido deve avere:
• Un nome univoco;
• un posto nella gerarchia degli oggetti;
• pu` essere connesso ad altri oggetti per inviare o ricevere segnali;
o
• deve avere un insieme di propriet`.
a
12. 2.1 La libreria Qt 10
2.1.1 Il Meta-Object System
Il Meta-Object System ` un estensione del C++ che rende il linguaggio
e
pi` adatto alla programmazione di GUI mediante componenti che sfruttan-
u
do le elevate prestazioni del C++ e che non potrebbero essere raggiunte
altrimenti. Questo si base su tre aspetti:
1. la classe QObject fornisce una classe base per gli oggetti che possono
usufruire del Meta-Object System;
2. la macro Q OBJECT all’interno della sezione privata della dichiarazione
di classe viene utilizzata per abilitare alcune funzionalit` del meta
a
oggetto come le propriet` dinamiche, ed il sistema di comunicazione
a
Signals and Slots;
3. il Meta-Object Compiler fornisce ad ogni QObject il codice necessario
per l’implementazione delle caratteristiche del meta oggetto.
Inoltre, per fornire i meccanismi di comunicazione tra oggetti mediante
Signals and Slots, il Meta-Object System mette a disposizione le seguenti
funzionalit`:
a
• QObject::metaObject(): restituisce il meta oggetto associato alla classe
• QMetaObject::className(): restituisce il nome della classe a tempo di
esecuzione
• QObject::inherits(): permette di discriminare se l’oggetto ` istanza di
e
una classe ereditata
• QObject::tr() e QObject::trUtf8(): permettono la traduzione di stringhe
per la propriet` di internazionalizzazione
a
• QObject::setProperty() e QObject::property(): permettono di leggere e
settare le propriet` dell’oggetto dinamicamente
a
• QMetaObject::newInstance(): costruisce una nuova istanza della classe
• qobject cast() utilizzato su un QObject da la possibilit` di eseguire un
a
cast dinamico dell’oggetto.
13. 2.1 La libreria Qt 11
2.1.2 Meta-Object Compiler
Il Meta-Object Compiler (MOC) ` un applicazione di Qt per la gestione
e
delle estensioni C++. In particolare esso si occupa di creare un file sorgente,
contenente il codice del meta oggetto, per ogni file sorgente contenente la
macro Q OBJECT o altre macro come PROPERTY e Q ENUMS. Questo
sorgente verr` poi incluso nel vecchio file o compilato e linkato all’implemen-
a
tazione della classe. La creazione del file contenente il codice per il meta
oggetto ` necessaria per implementare meccanismi come la comunicazione
e
tra gli oggetti, la gestione delle propriet` dinamicamente e le informazioni
a
dei tipi a runtime (RTTI). Un tipico file sorgente dove il MOC agisce `
e
mostrato di seguito:
c l a s s MyClass : p u b l i c QObject
{
Q OBJECT
public :
MyClass ( QObject ∗ p a r e n t =0) ;
MyClass ( ) ;
signals :
void mySignal () ;
public slots :
v o i d mySlot ( ) ;
};
La creazione dei sorgenti che contengono i meta dati pu` avvenire secon-
o
do due diverse modalit`: una che prevede l’utilizzo diretto del MOC addeb-
a
itando al programmatore l’onere di inserire delle regole per la gestione del
MOC all’interno dei makefile, l’altra che prevede l’utilizzo del tool qmake
che crea automaticamente i makefile con le regole idonee per il corretto
funzionamento del MOC.
2.1.3 Signals and Slots
Il sistema Signals and Slots implementa la comunicazione tra gli ogget-
ti. Questa ` una caratteristica peculiare di Qt che lo differenzia da altri
e
framework per GUI in circolazione.
Nell’ambito della programmazione di interfacce grafiche, ci si aspetta che
al variare di dati corrisponda la variazione di qualche elemento della GUI.
Nei vecchi framework per la programmazione di GUI, questo meccanismo
14. 2.1 La libreria Qt 12
viene implementato utilizzando dei riferimenti a delle funzioni detti callback.
I problemi principali che affliggono questo sistema sono due: innanzitutto
non ` type-safe, nel senso che non possiamo essere sicuri che la funzione
e
chiamante invochi una funzione callback con i parametri adeguati, in secondo
luogo, una funzione callback ` strettamente legata alla funzione chiamante,
e
quindi quest’ultima deve conoscere con precisione la funzione da invocare.
Il sistema Signals and Slots di Qt, rappresenta una valida alternativa
al meccanismo del callback. Ogni oggetto Qt ` caratterizzato dall’avere
e
una serie di segnali e di slot, alla quale il programmatore pu` aggiungere
o
quelli creati autonomamente. Un segnale viene emesso da un oggetto al
verificarsi di un determinato evento, mediante il metodo emit(), mentre lo
slot rappresenta l’azione, o la sequenza di azioni, da intraprendere quando
questo viene attivato dal segnale al quale ` collegato. in pratica uno slot
e
` l’equivalente di un metodo con degli opportuni argomenti in ingresso. A
e
differenza del meccanismo di callback, Signals and Slots ` type-safe, nel senso
e
che la firma del segnale emesso deve coincidere con la firma dello slot che
deve essere eseguito. Inoltre, segnali e slot sono disaccoppiati, ci` vuol dire
o
che un segnale non deve conoscere lo slot a cui ` collegato. La connessione
e
tra un segnale ed uno slot avviene mediante il metodo:
c o n n e c t ( Sender , SIGNAL ( s i g n a l ( ) ) , R e c e i v e r , SLOT( s l o t ( ) ) )
dove i parametri assumono il seguente significato:
→ Sender: l’oggetto (o il thread ) che invia il segnale;
→ SIGNAL(signal()): il segnale che viene emesso dal Sender;
→ Receiver: l’oggetto (o un thread ) che riceve il segnale;
→ SLOT(slot()): le funzioni che il receiver deve eseguire alla ricezione del
segnale.
La Fig. 2.1 mostra un esempio di connessione tra oggetti. Questo mec-
canismo prevede non solo la connessione tra segnale e slot, ma anche la
connessione tra due segnali, tra un segnale e pi` slot e tra pi` segnali ed uno
u u
slot. Ovviamente non ` contemplata la connessione tra due slot, in quanto
e
non ` possibile emettere uno slot.
e
Quando un segnale viene emesso, l’esecuzione dello slot avviene istan-
taneamente e solo al termine della sua esecuzione, il chiamante riprende il
15. 2.1 La libreria Qt 13
Fig. 2.1: Esempio di collegamento Signal/Solt.
controllo. Esiste anche la possibilit` di creare una coda di connessioni, in
a
questo caso l’esecuzione dello slot associato all’emissione di un segnale non
avviene istantaneamente.
La connessione tra segnale e slot pu` essere interrotta mediante la chia-
o
mata alla funzione disconnect().
L’unico punto a sfavore di questo sistema di comunicazione ` che risulta
e
essere circa 10 volte pi` lento, rispetto a chiamare direttamente la funzione
u
da eseguire. Questo tempo ` dovuto all’overhead richiesto per localizzare
e
l’oggetto, creare la connessione ed effettuare il marshall dei parametri. Tut-
tavia questo rallentamento influisce in minima parte nel tempo complessivo
di esecuzione del programma e rimane comunque pi` veloce dell’allocazione
u
di un nuovo oggetto mediante new.
Vediamo infine un esempio pratico dell’utilizzo del sistema Signal /
Slot. Si pu` notare come la creazione di un segnale avviene all’atto del-
o
la creazione della classe che definisce l’oggetto, mentre, la creazione di uno
slot oltre a richiedere la dichiarazione, come avviene per il segnale, deve
essere implementato allo stessa maniera di un metodo.
public slots :
void setValue ( int value ) ;
signals
v a l u e C h a n g e d ( i n t newValue ) ;
16. 2.1 La libreria Qt 14
void Counter : : SetValue ( i n t e v a l u e )
{
i f ( v a l u e != m v a l u e ) {
m v a l u e=v a l u e ;
emit valueChanged ( value ) ;
}
}
Couter a , b ;
QObject : : c o n n e c t (&a , SIGNAL ( v a l u e C h a n g e d ( i n t ) ) ,
&b , SLOT( s e t V a l u e ( i n t ) ) ) ;
a . s e t V a l u e ( 1 2 ) ; // a . v a l u e ( ) ==12, b . v a l u e ( ) ==12
b . s e t V a l u e ( 4 8 ) ; // a . v a l u e ( ) ==12, b . v a l u e ( ) ==48
Siano a e b due oggetti di tipo Counter. L’invocazione del metodo set-
Value() sull’oggetto a (uno slot pu` essere invocato anche come un normale
o
metodo) provoca la variazione dell’attuale valore dell’oggetto che emette il
segnale valueChanged(int), attivando di conseguenza lo slot dell’oggetto b
che provveder` ad assegnare il valore ricevuto come parametro.
a
2.1.4 L’architettura Model/View
Il framework Qt introduce lo schema di progettazione Model/View Con-
troller (MVC). Si tratta di un pattern architetturale molto usato nell’ingeg-
neria del software, che consiste nel separare nettamente il problema dei dati
dalla loro rappresentazione, con dei vantaggi enormi in termini di flessibilit`.
a
Il pattern ` cos` composto:
e ı
• il model: fornisce i metodi per accedere ai dati utili all’applicazione;
• il view: visualizza i dati contenuti nel model e si occupa dell’inter-
azione con utenti e agenti;
• il controller riceve i comandi dell’utente (in genere attraverso il view)
e li attua modificando lo stato degli altri due componenti.
Quando, come nel frmework Qt, il view ed il controller sono combi-
nati si ottiene l’architettura model/view. Questa ha anch’essa il fine ul-
timo di separare il modo il cui i dati sono memorizzati, dal modo in cui
sono presentati, ma con un’architettura pi` semplice. Questa separazione
u
17. 2.1 La libreria Qt 15
Fig. 2.2: Il pattern Model/View Controller.
permette di rappresentare gli stessi dati in modi differenti, e da la possi-
bilit` di implementare nuove views, senza dover cambiare la struttura dati
a
sottostante.
Per permettere la gestione flessibile dei dati da parte dell’utente, viene
introdotto il concetto di delegate. Questo elemento gestisce la conversione
dei dati, nello scambio tra model e view.
Lo schema dell’archittettura model/view in Qt ` presentato in Fig. 2.2.
e
Il model comunica con la sorgente dati, provvedendo ad interfacciarli
con gli altri componenti dell’architettura. La natura della comunicazione
dipende dal tipo di dati e dal modo il model ` implementato.
e
Il view ottiene dal model un sistema di indici riferito ai dati. Questi
indici verranno utilizzati per recuperare i dati dalla sorgente.
Nelle view standard, un delegate converte i singoli dati. Quando un
dato ` modificato, il delegate comunica direttamente con il model utilizzando
e
la sua indicizzazione.
La comunicazione tra queste componenti avviene mediante il sistema
Signals and Slots:
→ i segnali provenienti dal model informano il view del cambiamento nei
dati;
→ i segnali provenienti dal view contengono le informazioni nate dalle
iterazioni dell’utente con la visualizzazione;
→ i segnali provenienti dal delegate aggiornano model e view: nello speci-
fico informano il model se bisogna aggiornare o prelevare dei dati e il
18. 2.1 La libreria Qt 16
view se bisogna aggiornare la vista.
Ognuna delle componenti descritte sono implementate in Qt da clas-
si astratte che definiscono una interfaccia comune e, in alcuni casi, im-
plementano alcune propriet` di defautl. Le classi astratte necessitano di
a
essere sottoclassate per ottenere un set completo di funzioni necessarie ai
componenti.
Model
Tutti gli oggetti model in Qt derivano dalla classe astratta QAbstrac-
tItemModel. Questa classe implementa i metodi comuni a tutti i tipi di
model. E’ flessibile a sufficienza da permettere al view di rappresentare i
dati come tabelle, liste o alberi. Strutture dati complesse possono essere
modellati creando delle sottoclassi di QAbstractItemModel. Per le strutture
dati pi` comuni, Qt fornisce un’ampia scelta di sottoclassi. Per la gestione
u
del database MySql ad esempio, in questo progetto abbiamo utlizzato le
classi QSqlTableModel e QSqlRelationalTableModel.
View
Implementazioni complete sono fornite per diversi tipi di rappresen-
tazione: QListView visualizza i dati in formato lista, qtQTableView vi-
sualizza i dati di un modello in forma tabellare, mentre QTreeView mostra
i dati come lista gerarchica. Ognuna di queste classi deriva dalla classe as-
tratta QAbstractItemView. Tutte queste classi possono essere a loro volta
sottoclassate per ottenere visualizzazioni personalizzate.
Delegate
Diversamente dal pattern MVC, la progettazione Model/View non com-
prende una completa separazione delle componenti per la gestione delle iter-
azioni con l’utente. In generale il view ` responsabile della presentazione dei
e
dati e della gestione degli input da parte dell’utente. Per consentire maggior
flessibilit` nel modo in cui si ottengono questi input, le iterazioni con l’utente
a
vengono gestite dal delegate. Questo componente oltre a gestire gli input
dall’utente, include anche delle funzionalit` di rendering per la modifica di
a
oggetti nelle viste. Le classi base dei delegate sono: QAbstractItemDelegate
e QItemDelegate.
19. 2.2 Sistemi di coordinate 17
Questi aspetti del framework Qt verranno ripresi nei prossimi capitoli,
quando tratteremo l’implementazione del framework model/view all’interno
del nostro progetto.
2.2 Sistemi di coordinate
Verranno di seguito descritti due sistemi di coordinate, necessari per
poter lavorare con materiale mappale. Il World Geodatic System ` uno dei
e
tanti sistemi di riferimento per mappe, ed uno dei pi` usati.
u
2.2.1 Il sistema WGS84
Il World Geodatic System (WGS84) ` un sistema di riferimento terrestre,
e
cartesiano e geocentrico. Il sistema tiene conto della non perfetta sfericit`
a
della terra. Esso ` realizzato con una precisione di ±1m. Le coordinate sono
e
espresse in gradi secondo due parametri: latitudine e longitudine.
La longitudine, chiamata anche meridiano, giace perpendicolarmente
all’equatore e corre da un polo all’altro. E’ suddiviso in 360◦ , 180◦ nell’em-
isfero orientale e 180◦ nell’emisfero occidentale. Il meridiano nullo passa per
l’osservatorio di Greenwich, in Inghilterra.
La latitudine, chiamata anche parallelo, giace parallelamente all’equa-
tore. E’ suddivisa in 180◦ , 90◦ a nord dell’equatore e 90◦ a sud. Tra queste
coordinate si pu` indicare anche la quota sul livello del mare. Le coordinate
o
sono illustrate in Fig. 2.3.
Il WGS84 costituisce il sistema di coordinate utilizzato anche dai sistemi
Global Positioning System (GPS).
2.2.2 Il sistema cartesiano
Il sistema di coordinate cartesiano ` quello pi` diffuso in ambiti generali.
e u
Gli assi delle coordinate sono disposti perpendicolarmente tra loro e si in-
contrano in corrispondenza dell’origine. A seconda delle necessit`, l’origine
a
pu` essere posta in corrispondenza di un qualsiasi punto di riferimento.
o
Sull’asse x (ascissa) i valori di coordinata crescono generalmente da
sinistra a destra.
Sull’asse y (ordinate) crescono in base all’applicazione: da sotto a sopra
o da sopra a sotto. Nella computer grafica ad esempio l’origine corrisponde
20. 2.2 Sistemi di coordinate 18
Fig. 2.3: Il sistema di coordinate WGS84.
Fig. 2.4: Il sistema di coordinate cartesiano.
all’angolo visualizzato in alto a sinistra. In questo caso i valori negativi non
sono accettabili poich´ non corrispondono alla posizione di pixel. Questo
e
sistema di coordinate ` rappresentato in Fig. 2.4.
e
2.2.3 Conversione di coordinate
Nel rappresentare dati geografici su uno schermo, nasce la necessita di
operare una conversione di coordinate da un sistema sferico, come il WGS84,
in un sistema piano come quello cartesiano. Esistono diversi metodi di
proiezione di coordinate ma tutti questi comportano inevitabilmente anche
una distorsione. Non esiste una proiezione migliore, tutte si caratterizzano
per una determinata “semplicificazione“, occorre quindi solo scegliere quella
pi` adatta ad una determinata applicazione.
u
Gli obiettivi di massima da osservare per una proiezione sono:
21. 2.2 Sistemi di coordinate 19
Fig. 2.5: Esempi di proiezione su solidi
♦ l’equidistanza;
♦ isogonalit`, cio` il mantenimento degli angoli;
a e
♦ equivalenza delle aree.
Le proiezioni si distinguono per il solido che funge da superficie di proiezione.
Pertanto esistono proiezioni a cilindro, a cono e a livelli, come mostra-
to in Fig. 2.5. Ad esempio una proiezione a cilindro non subisce distor-
sione in corrispondenza dell’equatore, mentre avr` distorsione massima in
a
corrispondenza dei poli.
La proiezione utilizzata nelle mappe OpenStreetMap ` quella di Merca-
e
tore.
La proiezione di Mercatore
La proiezione di Mercatore ` una proiezione cartografica conforme e
e
cilindrica proposta nel 1569 dal geografo e cartografo fiammingo Gerard de
Cremer noto come Gerardus Mercator (italianizzato in Gerardo Mercatore).
La rappresentazione di Mercatore ` uno sviluppo cilindrico diretto mod-
e
ificato da un procedimento misto geometrico-analitico che rende le carte
isogoniche (angoli uguali). Essa ` diventata la proiezione cartografica pi`
e u
usata per le mappe nautiche per la sua propriet` di rappresentare linee di
a
costante angolo di rotta (linee lossodromiche) con segmenti rettilinei. Men-
tre la scala delle distanze ` costante in ogni direzione attorno ad ogni punto,
e
conservando allora gli angoli e le forme di piccoli oggetti (il che rende la
proiezione conforme), la proiezione distorce sempre pi` la dimensione e le
u
forme degli oggetti estesi passando dall’equatore ai poli, in corrispondenza
22. 2.3 I servers WMS 20
Fig. 2.6: La proiezione di Mercatore.
dei quali la scala della mappa aumenta a valori infiniti (secondo un grigliato
delle latitudini crescenti).
Lo schema della proiezione ` rappresentato in Fig. 2.6. Si pu` vedere
e o
come le proiezioni partono dal centro della terra passando per gli angoli
crescenti di latitudine fino ad intersecare la superficie di un cilindro. La
proiezione indicata con la linea rossa fuoriesce dal cilindro e pertanto non
pu` essere considerata. Per questa ragione gli angoli di latitudine sono da
o
considerarsi da +85,0511◦ fino a -85,0511◦ (invece che da +90◦ a -90◦ ). La
mappa piana risultante da questo tipo di proiezione ` illustrata in Fig. 2.7
e
2.3 I servers WMS
Per Web Map Service (WMS) si intende una specifica tecnica definita
dall’Open Geospatial Consortium atta a produrre mappe dinamiche di dati
spazialmente riferiti a partire da informazioni geografiche. Questo stan-
dard internazionale [4] definisce una mappa come la rappresentazione di
informazioni geografiche sottoforma di immagine digitale, idonea ad essere
visualizzata su browser web. Generalmente le mappe prodotte da un servizio
WMS sono rese in un formato immagine quale PNG, GIF o JPEG, occa-
23. 2.3 I servers WMS 21
Fig. 2.7: Risultato della proiezione di Mercatore.
sionalmente come elementi vettoriali in formato Scalable Vector Graphics
(SVG) o Web Computer Graphics Metafile (WebCGM); contrariamente a
un Web Feature Service (WFS), che restituisce dati vettoriali, o a un Web
Coverage Service (WCS), che restituisce dati raster.
Lo standard definisce tre operazioni:
♦ restituisce metadati a livello di servizio;
♦ restituisce una mappa dai parametri geografici e dimensionali definiti;
♦ restituisce informazioni sugli oggetti della cartografia visualizzata (opzionale).
Le operazioni del Web Map Service vengono invocate usando un client
che supporti il protocollo HTTP, in forma di Uniform Resource Locators
(URL). Il contenuto dell’URL dipende dalle operazioni richieste. In partico-
lare, la composizione dell’indirizzo va fatta indicando quali informazioni de-
vono essere visualizzate sulla mappa, quale porzione della Terra deve essere
rappresentata, il sistema di coordinate desiderato, il formato e le dimensioni
dell’immagine di output.
Qualora due o pi` mappe siano prodotte con gli stessi parametri ge-
u
ografici e di dimensione dell’immagine, i risultati possono essere sovrapposti
per produrre una mappa composita. L’uso di formati che supportano la
24. 2.3 I servers WMS 22
trasparenza (GIF o PNG per esempio) permette di visualizzare le parti di
mappa sottostanti; inoltre mappe diverse possono essere richieste a differenti
server. In questa maniera il Web Map Service abilita la creazione di una rete
di server cartografici che l’utente pu` utilizzare per costruire mappe person-
o
alizzate. Generalmente un Web Map Service non ` invocato direttamente;
e
vengono utilizzate applicazioni client che forniscono all’utente controlli in-
terattivi. Queste applicazioni client possono anche non essere web-based.
La specifica WMS ` diventata standard ISO19128 nel 2005.
e
2.3.1 Il progetto OpenStreetMap
L’OpenStreetMap ` un progetto collaborativo finalizzato a creare mappe
e
mondiali a contenuto libero. La caratteristica fondamentale dei dati ge-
e `
ografici presenti in OSM ` che possiedono una licenza libera. E cio` possi-
e
bile utilizzarli liberamente per qualsiasi scopo con il solo vincolo di citare la
fonte e usare la stessa licenza per eventuali lavori derivati dai dati di OSM.
Le mappe sono create usando come riferimento i dati registrati da dis-
positivi GPS portatili, fotografie aeree ed altre fonti libere. Sia le immagini
renderizzate che i dati vettoriali, oltre che lo stesso database di geodati, sono
rilasciati sotto licenza Creative Commons Attribution-ShareAlike 2.0.
OpenStreetMap ` stato ispirato da siti come Wikipedia. La comunit`
e a
collabora per integrare o modificare le mappe esistenti. Infatti ogni mappa
consultabile espone in evidenza l’etichetta Edit, per procedere alla mod-
ifica dei dati. Tutti gli utenti registrati possono caricare nei database del
progetto, le tracce GPS e modificare i dati vettoriali usando gli editor forniti.
2.3.2 I tiles
Servizi come Open Street Map, Google Maps o Yahoo! Map, forniscono
le mappe sottoforma di map tiles (piastrelle), cio` di immagini con una
e
dimensione fissa. Per ogni fattore di zoom, la mappa del globo ` suddivisa
e
in un reticolo di tiles sempre pi` fitto. Per il primo fattore di zoom, ad
u
esempio, l’intero globo ` compreso in un unico tile. Ad ogni incremento di
e
questo fattore, il numero di tile cresce come il quadrato, secondo la regola
descritta in Tabella 2.1. La risoluzione della mappa quindi, ` direttamente
e
proporzionale al livello di zoom.
25. 2.3 I servers WMS 23
Fig. 2.8: Una mappa con zoom differenti. Ad un incremento dello zoom i
tiles si quadruplicano.
Grazie a questa suddivisione delle mappe, ` sufficiente scaricare dal server
e
solo la porzione di mappa che ci interessa. Questa porzione viene calcolata
dal client in base alla posizione che vogliamo visualizzare e allo zoom. La
richiesta ` formulata sottoforma di indirizzo HTTP ad uno specifico server.
e
Per i server OSM, ad esempio, la richiesta di un tile allo zoom 16 assume
questa forma:
http://tile.openstreetmap.org/16/34271/22224.png
grado Zoom num. Tiles
0 1
1 2x2
2 4x4
n 2n x 2n
Tabella 2.1: Numero di tiles per fattore di zoom
2.3.3 Trasformazione di coordinate
La proiezione di Mercatore, utilizzata dal servizio OpenStreetMap, trasfor-
ma le coordinate geografiche in coordinate cartesiane bidimensionali. Queste
coordinate cartesiane sono espresse in pixel, poich` sono riferite alle immag-
e
ini tiles che costituiscono la mappa da visualizzare [9].
La longitudine va trasformata nella coordinata x mentre la latitudine
nella coordinata y. Il range di variazione della longitudine va da -180◦ a
+ 180◦ , pertanto la trasformazione comporterebbe valori negativi di pixel.
26. 2.3 I servers WMS 24
Per evitare ci` ` necessario shiftare tutto l’intervallo di longitudine di 180◦ .
oe
Pertanto la longitudine andr` da 0 a 360◦ . La regione R di variazione della
a
coordinata x, dove sono proiettate le coordinate Cartesiane assolute, dipen-
dono dal livello di zoom che andiamo a considerare. Per uno zoom pari a
2, la terra ` rappresentata da un reticolo di 2*2 tiles. Dato che ogni tile ha
e
dimensione pari a 256 pixel, la regione R avr` dimensione pari a 512*512
a
pixel.
La longitudine varia linearmente, quindi la coordinata x si ricava con la
formula:
λ + 180◦
x= ∗ R; con R = 2z ∗ t
360◦
dove λ= longitudine in gradi, R=range in pixel, z =livello di zoom,
t=dimensione singolo tile in pixel.
La latitudine varia da -85,0511◦ a + 85,0511◦ . Dato che i tiles sono
quadrati, la coordinata y ` mappata sullo stesso range R in pixel della
e
longitudine. La coordinata y si ricava dalla formula:
log(tan( π + ϕ ))
1−( 4 2
)
y= π
∗ R; con R = 2z ∗ t
2
dove ϕ= longitudine in gradi, R=range in pixel, z =livello di zoom,
t=dimensione singolo tile in pixel.
27. Capitolo 3
Il Public Lighting Manager
L’applicazione Public Lighting Manager ` stata progettata per operare in
e
uno scenario come quello rappresentato in Fig. 3.1. In fase di installazione
di una nuova rete pubblica di illuminazione, o in caso di adeguamento di
una rete esistente, vengono catalogati, mediante dispositivi portatili (PDA
o tablet) connessi alla rete, i dati dei singoli lampioni. Per ciascun apparato
sono registrati su un database remoto, le informazioni sulla locazione urbana,
la posizione GPS, i dati tecnici e l’indirizzo seriale. L’applicazione P.L.M.,
preleva questi dati dal database, e ricostruisce graficamente la disposizione
della rete d’illuminzione sulla mappa. Mediante l’interfaccia grafica, sem-
plice ed intuitiva, l’operatore pu` selezionare ed inviare comandi di gestione
o
ai lampioni, sia singolarmente che per gruppi.
Nei paragrafi successivi illustreremo il funzionamento dell’applicazione
P.L.M, nei suoi aspetti principali.
3.1 L’interfaccia
L’interfaccia del P.L.M. presenta una grafica semplice ed intuitiva. L’uso
pertanto ` immediato, anche per utenti non specializzati. Inoltre, la grafica
e
adottata si presta bene ad un successivo porting su dispositivi portatili con
touch-screen.
In Fig. 3.2 ` mostrata la schermata che si presenta all’utente dopo l’avvio
e
dell’applicazione e la connessione ad un database.Si possono distinguere sei
zone:
1. Menu
25
28. 3.1 L’interfaccia 26
Fig. 3.1: Scenario in cui opera il Public Lighting Manager
2. Barra degli strumenti
3. Vista mappa
4. Pannello filtro
5. Vista elenco
6. Barra di stato
Illustriamo nel dettaglio il loro utilizzo.
3.1.1 Menu
Nel menu sono raccolte tutte le funzioni dell’applicazione: dalla gestione
del database, alla modalit` di visualizzazione. E’ composto dai seguenti
a
elementi:
• File: gestione della connessione ad database e operazioni generali del-
l’applicazione.
29. 3.1 L’interfaccia 27
Fig. 3.2: Interfaccia grafica del P.L.M.
• Lamp: operazioni inerenti i lampioni (inserimento, eliminazione, mod-
ifica, ecc.).
• View: opzioni riguardanti le preferenze di visualizzazione.
• Help: accesso alla guida e alle informazioni generali sull’applicazione
P.L.M.
3.1.2 Barra degli strumenti
La barra degli strumenti ` composta da una serie di pulsanti che perme-
e
ttono di accedere alle funzioni principali mediante un semplice click. Con
riferimento alla Fig. 3.3, la barra ` suddivisibile come descritto di seguito:
e
(a) pannello database: funzioni di connessione ad un nuovo database,
apertura di file di connessione, chiusura connessione e modifica delle
voci del database.
(b) pannello mappa: funzioni di zoom in e zoom out, drag della mappa e
selezione rettangolare.
(c) pannello lamp: funzioni di inserimento di una nuova lamp, modifica,
eliminazione, accensione, spegnimento e richiamo delle informazioni.
30. 3.1 L’interfaccia 28
(a) (b) (c)
Fig. 3.3: Pannelli degli strumenti
(a) (b) (c)
Fig. 3.4: Rappresentaizione dei lampioni:(a) stato off; (b) stato on; (c)
stato di warning.
Questi pannelli si trovano tutti sul lato superiore della mappa, ma durante la
sessione possono essere spostati ai lati della mappa mediante trascinamento
con il mouse.
3.1.3 Vista mappa
In questa zona viene visualizzata la mappa OSM. Essa ` navigabile medi-
e
ante trascinamento con il mouse (in modalit` drag) e zoommabile mediante
a
i pulsanti sopra descritti. La mappa ` composta da due livelli sovrapposti:
e
1. livello mappa: ` sempre visibile e mostra il materiale offerto dal server
e
OSM
2. livello lamps: mostra la dislocazione dei lampioni sula mappa. Questi
sono rappresentati nell’attuale stato, con le icone in Fig. 3.4. Questo
livello pu` essere nascosto impostando il flag nel menu View
o
Cliccando sulle icone, ` possibile selezionare una o pi` lamps.
e u
Cliccando con il tasto destro sulla mappa, viene aperto il menu con-
testuale relativo alle lamps gi` selezionate.
a
3.1.4 Pannello filtri
Il pannello filtri opera sulla vista elenco (Par. 3.1.5). Si possono applicare
fino a tre regole che devono essere rispettate contemporaneamente. Per
instruzioni sull’utilizzo si veda il Par. 3.3.3.
31. 3.2 Gestione database 29
3.1.5 Vista elenco
Oltre alla vista su mappa, l’applicazione elenca le lamps in forma tabel-
lare. La vista elenco permette una rapida visione di tutti i lampioni instal-
lati. L’elenco pu` essere ordinato cliccando sull’header dei campi desiderati.
o
E’ possibile inoltre selezionare una o pi` lamps cliccando sulla rispettiva
u
riga.
Cliccando con il tasto destro sull’elenco, viene aperto il menu contes-
tuale relativo alle lamps gi` selezionate.
a
I campi da visualizzare sono impostati attraverso il menu View->Table
Column mentre l’intera tabella pu` essere nascosta agendo sul flag Show
o
Table.
3.1.6 Barra di stato
Nella barra di stato appaiono, sulla sinistra, i messaggi dell’applicazione
in risposta dei comandi impartiti dall’utente e i tool tip mentre sulla destra
sono sempre visibili le coordinate attuali (riferite alla croce al centro dello
schermo) e il livello di zoom corrente.
3.2 Gestione database
Come illustrato in Fig. 3.1, il software P.L.M. legge i dati relativi ai
lampioni da un database esterno, che pu` essere raggiunto attraverso la rete
o
internet o attraverso una rete locale. Da questi dati ne ottiene un model,
ossia una copia temporanea dei record che servono per poter rappresentare
i lampioni e per poterli indirizzare.
Lo schema del database e di tipo “relazionale” ed ` riportato in Fig. 3.5.
e
La flessibilit` di questa particolare struttura, permette all’utente finale di
a
integrare il database non solo di nuove lamps, ma anche di nuovi “attributi”
per queste, senza limite alcuno. La modifica del database sar` trattata nei
a
prossimi paragrafi.
3.2.1 Avviare una nuova connessione
Cliccando su ( File > New Connection) si apre all’utente la finestra
di dialogo in Fig. 3.6 con i seguenti campi:
32. 3.2 Gestione database 30
Streets
strade
Lamps 1
lampioni id int
id int streetName varchar
longitude double
latitude double n Groups
streetId int gruppi
foreign key
1
n id int
groupId int groupName varchar
foreign key
n
bodyId int Bodies
foreign key strutture
1
bodyDate date n id int
bulbId int bodyName varchar
foreign key bodyImage BLOB
bulbDate date n
operatorId int Bulbs
lampade
foreign key 1
id int
address varchar
bulbName varchar
Operators
operatori
1
id int
operatorName varchar
Fig. 3.5: Struttura del database
Fig. 3.6: Finestra di dialogo per una nuova connessione
• Host Name: l’indirizzo IP del database in rete. Nel caso si utilizzi un
database locale questo valore ` localhost;
e
• User Name: l’utente con i diritti di lettura e scrittura del database;
• Password: parola segreta per l’accesso;
• Database Name: un server pu` contenere pi` database, occorre quindi
o u
specificare il nome al quale si fa riferimento.
Compilati i campi si pu` decidere se salvare la connessione in un file XML
o
( Save), in modo da non doverli reinserire successivamente, o se procedere
con la connessione al database ( Connect).
33. 3.2 Gestione database 31
3.2.2 Aprire un file di connessione
Il pulsante ( File > Open connection file) permetter di aprire una
connessione salvata su file XML.
Il file di connessione deve avere la seguente struttura:
<P L A d m i n i s t r a t o r >
<Database> Nome d e l d a t a b a s e </Database>
<Pass> Password </Pass>
<User> Nome u t e n t e </User>
<Host> I n d i r i z z o h o s t </Host>
</ P L A d m i n i s t r a t o r >
L’applicazione verifica prima la presenza del root tag <PLAdministra-
tor>, in tal caso procede con lo scaricamento dei dati, altrimenti restituisce
un messaggio di errore.
3.2.3 Modifica database
L’editor del database consente di aggiungere, eliminare o modificare tutte
le voci del database. Si pu` accedere al database editor cliccando su
o (
File > Database editor). La finestra ` composta da pi` widget, accessibili
e u
facendo click sulle icone a sinistra.
Scheda Lamps
In questa scheda (Fig. 3.7(a)) ` possibile inserire una nuovo lampione a
e
coordinate da specificare. Ad ogni lampione ` associata una serie di infor-
e
mazioni come la strada ove ` ubicato ( Street), a quale gruppo appartiene
e
( Group), su che tipo di supporto ` montato ( Body Type) e in che data `
e e
stato installato( Body Date), che tipo di lampada monta ( Bulb Type) e la
data dell’ultima sostituzione ( Bulb Date), l’operatore che ha effettuato le
ultime modifiche ( Operator) ed infine l’indirizzo in formato esadecimale del
lampione ( Digital Address). Parte di queste informazioni vengono scelte at-
traverso menu a tendina, le cui voci vengono prelevate da tabelle relazionate,
che possono essere editate dalle schede seguenti.
34. 3.2 Gestione database 32
(a) (b)
Fig. 3.7: Schede (a)“Lamps” e (b)“Groups”
Scheda Groups
La definizione di un “group” ha lo scopo di facilitare la selezione di
un insieme di lamps che rispondono a determinate caratteristiche definite
dall’utente. Si possono ad esempio definire gruppi in base all’ubicazione
(quartiere o zona), oppure in base alle caratteristiche di sezionamento della
linea elettrica.
Per aggiungere un “group” (Fig. 3.7(b)) specificarne il nome ( Name) e
cliccare sul pulsante Add.
Per modificare un “group”, effettuare doppio click sulla riga e cliccare su
Save, per eliminarlo selezionare la riga e cliccare su Delete.
Scheda Streets
E’ l’elenco delle strade dove sono ubicate le lamps. Conoscere la “vi-
a” di ubicazione di un lampione, ne permette la rapida localizzazione nel
sistema urbano. Inoltre, grazie alle funzioni che vedremo pi` avanti, tale in-
u
formazione ci permetter` di selezionare tutti gli apparati situati nella stessa
a
strada.
Per aggiungere una “street” (Fig. 3.8(a)) specificarne le tipologia ( Type),
il nome ( Name). e cliccare sul pulsante Add.
Per modificare una “street”, effettuare doppio click sulla riga e cliccare
su Save, per eliminarla selezionare la riga e cliccare su Delete.
35. 3.2 Gestione database 33
(a) (b)
Fig. 3.8: Schede (a)“Streets” e (b)“Bodies”
Scheda Bodies
Elenco delle strutture dei lampioni. Oltre alla sigla body name, pu`
o
essere associata una immagine che presenta graficamente all’utente il fattore
di forma del lampione.
Per aggiungere una struttura (Fig. 3.8(b)) specificarne il nome ( Name)
e cliccare sul pulsante Add.
Per caricare una immagine inserire il percorso del file nel campo Image...
Per modificare un “body”, effettuare doppio click sulla riga e cliccare su
Save, per eliminarlo selezionare la riga e cliccare su Delete.
Scheda Bulbs
Elenco dei diversi tipi di lampade utilizzate. In base alle diverse neces-
sit` di illuminazione possono essere utilizzate tecnologie differenti (lampade
a
LED, a scarica, alogene ecc.). In sviluppi futuri, questa specifica sar` utile
a
per diversificare il controllo software delle lampade.
Per aggiungere una lampada (Fig. 3.9(a)) specificarne il nome ( Name),
la potenza in watt ( Power) e cliccare sul pulsante Add.
Per modificare un “bulb”, effettuare doppio click sulla riga e cliccare su
Save, per eliminarlo selezionare la riga e cliccare su Delete.
36. 3.3 Selezione e filtraggio 34
(a) (b)
Fig. 3.9: Schede (a)“Bulbs” e (b)“Operators”
Scheda Operators
In un contesto dove un gruppo di operatori lavora sulla stessa linea,
pu` essere utile conoscere quale tecnico ha operato l’ultimo intervento sul
o
lampione.
Per aggiunger un nuovo operatore (Fig. 3.9(b)) specificarne nome e cog-
nome ( Name, Surname) e cliccare su Add.
Per modificare un “operator”, effettuare doppio click sulla riga e cliccare
su Save, per eliminarlo selezionare la riga e cliccare su Delete.
3.2.4 Chiusura della connessione
Il pulsante ( File > Close connection file) disconnette l’applicazione
dal database. In questo caso sia la vista mappa che la vista elenco vengono
“pulite” dalle lamps Questo comando viene eseguito automaticamente anche
nel caso in cui ci si avvii una nuova connessione.
3.3 Selezione e filtraggio
In un uso “a regime”, ` facile pensare che ci si possa trovare a gestire
e
una rete di illuminazione pubblica molto vasta, con un numero di lampioni
nell’ordine delle migliaia di unit`. Assume quindi particolare importanza
a
37. 3.3 Selezione e filtraggio 35
Fig. 3.10: Scheda “Operators”
l’utilizzo di strumenti che permettano di operare la selezione delle lamps in
modi diversi, secondo le varie necessit`.
a
3.3.1 Selezione da mappa
Questa selezione viene effettuata mediante la vista mappa. In modalit`
a
Move map ( ) ` possibile selezionare un lampione cliccando sul simbolo
e
all’interno della mappa. Selezioni multiple sono possibili tenendo premuto il
tasto Ctrl e facendo click sulle lamp desiderate. In modalit` Rect selection
a
( ) i lampioni possono essere selezionati tracciando un rettangolo sulla
zona scelta. I lampioni all’interno del rettangolo vengono cos` selezionati.
ı
La procedura di deselezione funziona secondo lo stesso principio.
3.3.2 Selezione da tabella
In tabella appaiono tutti i lapioni sottoforma di elenco. La selezione si
pu` effettuare cliccando su una riga della tabella. Tenendo premuto il tasto
o
sinistro e muovendo il mouse ` possibile selezionare record contigui. Per
e
selezioni multiple discontigue, invece, ` sufficiente tenere premuto il tasto
e
Ctrl e cliccare sui record desiderati. Pu` essere utile, ai fini della selezione,
o
ordinare l’elenco delle lamps in base ai valori di un determinato campo; per
38. 3.4 Invio comandi 36
Fig. 3.11: Strumento di selezione in base a filtro
fare ci` basta cliccare sugli header della tabella e procedere con la selezione.
o
La procedura di deselezione funziona secondo lo stesso principio.
3.3.3 Selezione con filtro
Lo strumento filtro (Fig. 3.11) permette di selezionare le lamps mediante
l’impostazione di determinate regole, che devono essere rispettate contem-
poraneamente. E’ possibile selezionare per gruppo ( Group), per strada (
Street) o per il tipo di lampada ( Bulb).
I filtri vengono attivati cliccando sul Radio Button Filter o Select; nel
primo caso vengono elencati solo i lampioni che rispettano le regole selezion-
ate, nel secondo caso vengono mostrati tutti i lampioni ma sono selezionati
solo quelli che rispettano le regole selezionate.
3.4 Invio comandi
Al momento del primo rilascio dell’applicazione, non esiste ancora una
interfaccia hardware definita, pertanto i comandi di output sono simulati e
limitati all’accensione e allo spegnimento delle lamps.
I comandi si applicano ai lampioni selezionati, pertanto prima di inviare
un comando occorre selezionare una o pi` lamps secondo i metodi descritti
u
nei paragrafi precedenti.
Il comando di accensione viene inviato cliccando il pulsante , mentre
il comando di spegnimento viene inviato cliccando su . Ad ogni comando
le icone dei lampioni cambiano in base al nuovo stato.
39. 3.4 Invio comandi 37
Tutte le operazioni di output pengono tracciate sul file di log log file.txt.
40. Capitolo 4
Implementazione software
L’applicazione Public Lighting Manager ` stata sta scritta in linguag-
e
gio C++, mediante Qt Creator IDE ver.2.0.1, un potente ambiente di
sviluppo integrato e multipiattaforma, basato sul framework Qt ver.4.7.0
(32 bit), il tutto sotto sistema operativo Linux Ubuntu 10.010.
Nei capitoli successivi illustreremo il principio di funzionamento e l’im-
plementazione in codice, focalizzando l’attenzione sulle classi principali e le
routine pi` importanti.
u
4.1 Gestione della mappa
Il sottoprogetto QMapControl implementa una widget per la gestione e
la visualizzazione delle mappe. E’ basato su un progetto open-source [12] e
opportunamente modificato per incontrare le necessit` del nostro progetto.
a
La widget offre diverse peculiarit`:
a
• ` compatibile con diversi map provider ;
e
• si possono creare oggetti personalizzati da rappresentare nella mappa;
• gli oggetti possono essere posizionati a qualsiasi coordinata;
• la navigazione della mappa ` personalizzabile.
e
In questo contesto analizzeremo le caratteristiche principali che hanno
riguardato il nostro progetto, mentre per una spiegazione pi` dettagliata si
u
rimanda al sito dello sviluppatore.
38
41. 4.1 Gestione della mappa 39
4.1.1 Struttura di QMapControl
Come abbiamo visto nel paragrafo precedente la widget che andiamo a
considerare deve essere in grado di rappresentare allo stesso tempo la mappa
fornita da un opportuno provider, nel nostro case OpenStreetMap, ed inoltre
degli oggetti su di essa, che devono poter essere spostati senza variare la loro
posizione in relazione alla mappa. La realizzazione pertanto si avvale di una
struttura a livelli (layer).
Classe MapControl: ` la classe principale, la widget vera e propria. Qui
e
vengono istanziati i vari layer ed implementati i controlli necessari, come
ad esempio il panning delle mappe. Un oggetto MapControl deve essere
istanziato passando come parametro un QSize che impone le dimensioni
della widget in un certo layout. Queste saranno le dimensioni di riferimento
di tutti i layer istanziati, e quindi della mappa stessa.
Classi Geometry: sono gli oggetti che possiamo rappresentare sulla map-
pa. La classe Geometry implementa i metodi di base di tutti gli oggetti. Da
questa vengono derivate le classi Point e Light.
Classi Layer: sono i livelli che compongono la mappa. Ci sono due tipi di
layer: GeometryLayer e MapLayer, ma entrambi condividono gli stessi metodi.
Classe MapAdapter: ` una classe astratta e fornisce l’interfaccia dei meto-
e
di necessari alla widget, che dovranno essere implementati in modo diverso
a seconda dei server WMS che verranno utilizzati. In questo progetto viene
utilizzato il servizio OpenStreetMap, quindi le uniche classi derivate saranno
la TileMapAdapter, che gestisce l’elaborazione delle richieste ai tiles server e
la classe OSMMapAdapter, specifica per i server OperStreetMap.
4.1.2 Le geometrie
Le caratteristiche delle geometrie utilizzate nelle mappe, e i metodi da
esse supportate, sono specificate nelle Simple Feature Specification dell’Open
Geospatial Consortium [7]. La classe base, Geometry, implementa i metodi
comuni a tutte le geometrie. Da questa vendono derivate classi via via pi`
u
complesse, che aggiungono nuovi metodi a quelli della classe base.
In questa tesina ci siamo limitati all’utilizzo delle classi Point e Light.
Mentre la prima fa parte del progetto originale del QMapControl, la seconda,
che rappresenta l’oggetto “lampione” sulla mappa, ` stata implementata ad
e
hoc per rispondere alle necessit` del presente progetto.
a
42. 4.1 Gestione della mappa 40
Classe Geometry
Contiene sia metodi esplicitati che metodi virtual, da implementare nelle
sottoclassi. Elenchiamo i pi` importanti:
u
• parentGeometry(): in caso di oggetti derivati, restituisce un puntatore
all’oggetto “padre” altrimenti un puntatore a se stesso;
• setVisible(bool visible): imposta il flag di visibilit`, ;
a
• boundingBox(): metodo virtuale, restituisce un oggetto di tipo QRect,
con le dimensioni del rettangolo che contiene la geometria (Bounding
Box ).
Di particolare importanza ` il segnale geometryClicked(), che viene emes-
e
so quando l’utente clicca all’interno della bounding box di un oggetto. Un
oggetto ` cliccabile se il layer che lo contiene ` cliccabile.
e e
Classe Point
Un Point ` una Geometry dotato di coordinate geografiche. Questa classe
e
pu` essere utilizzata anche per disegnare una QPixmap, o una QWidgets, in
o
un determinato punto, basta chiamare il relativo costruttore.
Quando si disegna una pixmap, occorre tener presente che si sta aggiun-
`
gendo il punto in una GeometryLayer. E possibile aggiungere un punto anche
ad una MapLayer, ma questo dovrebbe essere fatto solo se il punto mantiene
costante la sua posizione. Infatti mentre il GeometryLayer viene ridisegna-
to ad ogni cambiamento del punto, il MapLayer viene ridisegnato sono in
corrispondenza della modifica della finestra principale (viewport).
Per una immagine o una widget sono possibili diversi allineamenti rispet-
to al punto specificato. La Fig. 4.2 mostra le diverse possibilit`.
a
La classe Point permette di scalare l’immagine associata in base allo
zoom. Per fare ci`, occorre impostare con il metodo setBaseLevel() il fat-
o
tore di zoom in corrispondenza del quale l’immagine deve avere le dimen-
sioni originali. Per altri fattori di zoom l’immagine verr` cos` ingrandita o
a ı
rimpicciolita automaticamente (Fig. 4.1).
I metodi setMinSize() e setMaxSize() permettono di impostare valori di
massima e di minima dimensione per i pixmap o le widget associate al point,
per evitare ad esempio che a bassi livelli di zoom le immagini non siano pi`
u
visibili.
43. 4.1 Gestione della mappa 41
Fig. 4.1: Zoom di una geometria
Fig. 4.2: Allineamento di una geometria
Il metodo Touches() restituisce un valore booleano a seconda che il punto
passato in argomento tocchi o meno il punto della classe. Se al punto `
e
associata una pixmap, il controllo della collisione avviene considerando la
bounding box della figura.
Classe Light
La classe Light ` una sottoclasse di Point, che abbiamo introdotto al
e
progetto originale QmapControl, per la rappresentazione dei lampioni sulla
mappa. Ogni Light ` identificato da un numero intero ( id), che corrisponde
e
all’indice della chiave primaria del lampione nel database. In questo modo
si assicura la corrispondenza degli oggetti grafici sulla mappa con i record
del database.
La classe implementa quattro metodi che sono anche slot:
• getId(), restituitsce l’identificativo del lampione.
• setOnState(bool), imposta lo stato on/off per il lampione. In base
allo stato, la pixmap associata viene cambiata con l’immagine di un
lampione acceso o spento.
44. 4.1 Gestione della mappa 42
• SetWarningState(bool) imposta lo stato di warning per il lampione.
In caso di warning positivo, il lampione viene rappresentato da una
pixmap con un punto interrogativo, a segnalare lo stato anomalo.
Questo stato ha priorit` sullo stato on/off.
a
• setToMove(bool), viene chiamato quando l’utente vuole modificare la
posizione del lapione sulla mappa.
4.1.3 I livelli
La visualizzazione delle mappe nella widget QMapControl ` organizzata
e
in livelli (detti anche layers). Ci sono due tipi di layer, i MapLayer e i
GeometryLayer. I primi possono visualizzare contenuti statici, come mappe,
ma anche geometrie, i secondi possono rappresentare solo le geometrie. La
differenza sta nella modalit` con cui questi layer vengono aggiornati: mentre
a
gli oggetti appartenenti ad una GeometryLayer vengono ridisegnati ogni volta
che cambiano posizione, gli oggetti appartenenti ad un MapLayer vengono
ridisegnati solo in corrispondenza dell’aggiornamento dell’intera schermata
(offscreen).
Per il resto le due classi hanno gli tessi metodi, ereditati dalla classe
madre Layer. I metodi pubblici addGeometry() e removeGeometry() sono
utilizzati nella gestione delle geometrie del layer, mentre lo slot setVisible()
ne impone la visibilit`.
a
Il segnale geometrySelect(int ID) viene emesso quando viene selezionato,
mediante click, l’oggetto con indice ID appartenente al layer.
Ogni livello ` contraddistinto da un nome e tutti sono gestiti dalla classe
e
LayerManager. Questa classe conserva tutti i parametri necessari alla rapp-
resentazione delle mappe. Le coordinate del centro della finestra, le misure
dell’area visibile all’utente e il livello di zoom. Le misure dell’area visibile
(offscreenViewport) possono essere espresse in coordinate cartesiane o in
coordinate di proiezione. Le coordinate di proiezione sono le coordinate in
pixel relative allo specifico zoom. La widget principale fa riferimento a ques-
ta classe per variare il modo di rappresentazione della mappa, chiamandone
i relativi metodi. A sua volta LayerManager passa questi comandi a tutti i
layer presenti.
Quando si istanzia un nuovo Layer, occorre passare al costruttore il pun-
tatore ad un MapAdapter, che regola la conformit` del layer con il servizio
a
45. 4.1 Gestione della mappa 43
di mappe online. La classe MapAdapter verr` illustrata nel prossimo para-
a
grafo.
4.1.4 Richiesta dei Tiles
La classe MapAdapter permette alla widget di generare nel formato cor-
retto, la richiesta dei dati cartografici per diversi servers.
Da MapAdapter vengono pertanto derivate due sottoclassi:
• TileMapAdapter, che dialoga con servers basati su immagini tiles, come
OpenStreetMap o Google Maps;
• WMSAdapter, che dialoga con servers di tipo WMS.
La classe TileMapAdapter implementa la conversione di coordinate, sec-
ondo la procedura vista nel Par.2.3.3. Queste operazioni sono necessarie per
formulare correttamente la richiesta di nuovi tiles, per una data posizione e
per un dato fattore di zoom. L’interrogazione del server avviene mediante
protocollo HTTP, componendo una stringa del tipo:
http://tile.openstreetmap.org/%1/%2/%3.png
I caratteri %1, %2, e %3 sono dei “segnaposti” che grazie alla funzione
query(int x,int y,int z) vengono sostituiti con opportuni valori:
• %1 rappresenta lo zoom, indicato come numero intero (da 0 a 18 per
server OSM);
• %2 coordinata x del tile (da 0 a 2z − 1, con z=fattore zoom);
• %3 coordinata y del tile (da 0 a 2z − 1, con z=fattore zoom).
Le coordinate dei tiles, per fattori di zoom da 0 a 3, sono rappresentate
in Fig. 4.3.
L’indirizzo dell’host e il formato della richiesta per un certo server,
vengono fornite dalle sottoclassi di TileMapAdapter. Per il server Open-
StreetMap viene utilizzata la classe OSMMapAdapter.
46. 4.2 Struttura del progetto 44
Fig. 4.3: Ccoordinate dei tiles, per fattori di zoom 1,2 e 3
4.2 Struttura del progetto
In questo paragrafo andiamo ad elencare i file che compongono il progetto
P.L.M.
• pladministrator.cpp: ` la classe principale, l’applicazione vera e pro-
e
pria. Qui sono implementate le funzioni principali dell’interfaccia che
illustreremo nei prossimi paragrafi;
• combodelegate.cpp: ` qui implementata l’omonima classe, utilizzata
e
come delegate del mapper in LampPage (vedi Par.??), per l’indiciz-
zazione corretta delle voci;
• conndialog.cpp: finestra di dialogo per aprire una nuova connessione
ad un database.
• dbmanager.cpp: finestra di dialogo che riunisce una serie di widget (
QStackWidget), implementate nel file pages.cpp, per la gestione del
database dei lampioni.
• pages.cpp: l’insieme delle widget utili all’editing del database. Qui
sono implementate tutte le operazioni di inserimento, modifica e can-
cellazione dei record. Inoltre sono specificate le funzioni utili a man-
tenere l’integrit` del database.
a
• dialogs.cpp: qui sono implementate le finestre di dialogo per la modi-
fica/visualizzazione delle lamps.
• main.cpp: classe per l’avvio dell’applicazione.
47. 4.3 Database 45
• proxymodel.cpp: questa classe incapsula un modello predefinito, ma
stabilisce delle regole per la visualizzazione dei record.
4.3 Database
La struttura del database ` rappresentata in Fig. 4.4. Secondo lo schema
e
classico dei database relazionali, alcuni campi della tabella principale Lamps,
sono costituiti dalle chiavi dei valori di tabelle “attributi”. Questa caratter-
istica permette di aggiornare ed integrare gli attributi secondo le necessit`
a
dell’utente finale, in modo illimitato e flessibile.
Le istruzioni SQL che realizzano questa struttura sono le seguenti:
CREATE TABLE IF NOT EXISTS streets (
id INT NOT NULL AUTO_INCREMENT ,
streetName VARCHAR(40) UNIQUE,
PRIMARY KEY (id))ENGINE=InnoDB);
CREATE TABLE IF NOT EXISTS groups (
id INT NOT NULL AUTO_INCREMENT ,
groupName VARCHAR(40) UNIQUE,
PRIMARY KEY (id))ENGINE=InnoDB);
CREATE TABLE IF NOT EXISTS bodytype (
id INT NOT NULL AUTO_INCREMENT ,
bodyName VARCHAR(40) UNIQUE,
bodyImage BLOB,
PRIMARY KEY (id))ENGINE=InnoDB);
CREATE TABLE IF NOT EXISTS bulbtype (
id INT NOT NULL AUTO_INCREMENT ,
bulbName VARCHAR(40) UNIQUE,
PRIMARY KEY (id))ENGINE=InnoDB);
CREATE TABLE IF NOT EXISTS operators (
id INT NOT NULL AUTO_INCREMENT ,
operatorName VARCHAR(40) UNIQUE,
PRIMARY KEY (id))ENGINE=InnoDB);
48. 4.3 Database 46
CREATE TABLE IF NOT EXISTS lamps (
id INT NOT NULL AUTO_INCREMENT ,
latitude DOUBLE,
longitude DOUBLE,
streetId INT ,
groupId INT ,
bodyId INT ,
bodyDate DATE NOT NULL,
bulbId INT ,
bulbDate DATE NOT NULL,
operatorId INT ,
address VARCHAR(40),
PRIMARY KEY (id),
FOREIGN KEY (streetId) REFERENCES streets(id),
FOREIGN KEY (groupId) REFERENCES groups(id),
FOREIGN KEY (bodyId) REFERENCES bodytype(id),
FOREIGN KEY (bulbId) REFERENCES bulbtype(id),
FOREIGN KEY (operatorId) REFERENCES operators(id)
)ENGINE=InnoDB);
Queste istruzioni sono invocate nella routine dbConnect(), che vedremo
nel dettaglio pi` avanti.
u
4.3.1 Connessione
Come abbiamo visto nel capitolo precedente, l’utente pu` scegliere se
o
specificare una nuova connessione o aprire un file contentente i parametri di
una connessione salvata.
Nal primo caso la funzione newConenction istanzia un nuovo oggetto della
classe ConnDialog, presente nell’omonimo file. Si tratta di una finestra di
dialogo dove inserire i quattro parametri necessari:
• Database Name;
• Password;
• User Name;
49. 4.3 Database 47
Streets
strade
Lamps 1
lampioni id int
id int streetName varchar
longitude double
latitude double n Groups
streetId int gruppi
foreign key
1
n id int
groupId int groupName varchar
foreign key
n
bodyId int Bodies
foreign key strutture
1
bodyDate date n id int
bulbId int bodyName varchar
foreign key bodyImage BLOB
bulbDate date n
operatorId int Bulbs
lampade
foreign key 1
id int
address varchar
bulbName varchar
Operators
operatori
1
id int
operatorName varchar
Fig. 4.4: Struttura del database
• Host Address.
Se i dati inseriti sono validi viene chiamata la funzione connectPLA().
connDialog implementa anche la funzione Save, che permette di salvare
i parametri inseriti in un file XML. Le librerie Qt offrono una opportuna
API per la lettura/scrittura di file XML. In questo caso ` utilizzata una
e
interfaccia DOM (Document Object Model), per creare una struttura ad
albero con i tag specificati dall’utente. L’“albero“ cos` creato viene salvato
ı
su file mediante uno stream di testo ( QTextStream).
La funzione openConnectionFile(), viene invocata nel caso in cui l’utente
scelga di aprire un file di connessione salvato. L’interfaccia DOM converte
il documento XML nella struttura ad albero corrispondente. La funzione
riconosce la radice nel tag <PLAdministrator>, ed individia i nodi “figlio”
che contengono i campi necessari alla connessione, quindi viene chiamata la
funzione connectPLA.
50. 4.3 Database 48
Funzione dbConnect
Questa funzione ` quella che avvia la connessione vera e propria al
e
database. Il modulo QtSql fornisce una efficiente interfaccia per l’accesso
a diversi tipi di database SQL.
Un nuovo oggetto QSqlDatabase viene creato grazie al metodo addDatabase(),
specificando quale driver utilizzare per la connessione: nel nostro caso QMYSQL.
Impostati le credenziali d’accesso, il metodo open() stabilisce, di fatto,
la connessione.
In questa funzione vengono create le tabelle del database necessarie,
qualora non fossero gi` presenti. Il metodo exec() dell’oggetto QSqlQuery
a
esegue le opportune query viste nel paragrafo precedente.
In caso di successo la funzione dbConnect() restituisce un valore booleano
true
Funzione connectPLA()
La routine ha il compito di avviare tutte le procedure per la visualiz-
zazione dei dati, in seguito ad una avvenuta connessione.
Le chiamate a initializeModel() e initializeView(), istanziano l’architettura
model/view (vedi Par 4.4).
L’interfaccia viene divisa, mediante nuovo oggetto QSplitter, cos` da per-
ı
mettere la visualizzazione tabellare delle lamps (funzione createListGroup-
Box()). Vengono qui create anche le opportune connessioni signal/slot, per il
corretto interfacciamento della tabella con il resto dell’applicazione (funzione
createConnection()).
Ottenuti i dati dal database non rimane che graficare sulla mappa le
lamps, in base alla loro geolocalizzazione. Questo compito ` realizzato dalla
e
funzione drawLamps().
La lettura dello stato attuale dei lampioni, con la conseguente modifica
dell’icona sulla mappa, viene effettuata da due funzioni: readStatusLamps()
che legge da un file txt esterno lo stato on/off dei lampioni e da read-
WarningLamps() che legge da un file txt esterno quali lampioni presentano
anomalie o malfunzionamenti.
51. 4.3 Database 49
Funzione disconnectPLA()
Questa funzione pu` essere invocata manualmente dall’utente mediante
o
il comando Close Connection, oppure automaticamente quando si avvia una
nuova connessione. L’effetto della procedura infatti ` quello di salvare lo sta-
e
to delle lamps(funzione saveStatusLamps()), cancellare le variabili di stato
di queste ( warningLamps, turnedOnLamps), resettare sia model che prox-
yModel e chiudere la connessione ad database (metodi removeDatabase() e
close()).
4.3.2 Database Editor
La classe DBManager, implementa l’interfaccia di modifica del database.
Si tratta di una finestra di dialogo (sottoclasse di QDialog) strutturata come
una QStackedWidget, ossia un insieme widget o pages, che vengono visualiz-
zate all’interno della stessa finestra. Si pu` passare da una widget all’altra
o
mediante un sistema di icone.
Ogni page rappresenta una tabella del database. Il costruttore DBMan-
ager() istanzia quindi le sei widget e ne organizza la paginazione.
Esso riceve come argomento un puntatore al model principale, che a sua
volta verr` passato alle pages. Secondo il concetto dell’architettura MVC
a
infatti, le modfiche al database passano per la modifica del model associato.
Gli unici metodi della classe DBManager sono createIcons() e changePage(),
che definiscono la navigazione tra widget attraverso le icone associate.
Nel file pages.cpp sono implementate le sei widget dell’editor:
• LampPage: widget per i lampioni;
• GroupPage: widget per i gruppi
• StreetPage: widget per l’elenco vie;
• BodyPage: widget per l’elenco supporti;
• BulbPage: widget per l’elenco lampade;
• OperatorPage: widget per l’elenco degli installatori.
La classe LampPage permette l’overload di tre diversi costruttori che
differiscono per il tipo ed il numero di argomenti:
52. 4.3 Database 50
• LampPage(QSqlRelationalTableModel *tableModel,QWidget *parent): viene
utilizzato nel Database Editor e riceve come argomento solo il model
principale;
• LampPage(QPointF* point, QSqlRelationalTableModel *tableModel,QWidget
*parent): rispetto al precedente ha in pi` l’argomento di tipo QPointF.
u
Questo costruttore viene invocato nel caso in cui l’untente decida di
inserire una nuova lamp in un determinato punto della mappa (co-
mando add Lamp). In questo caso l’editor della lamp si apre con i
campi lonEditor e latEditor gi` completati con le coordinate del punto
a
nell’argomento.
• LampPage(QModelIndexList indexList, QSqlRelationalTableModel *table-
Model, bool ReadOnly,QWidget *parent): riceve come argomento la lista
delle righe selezionate ( QModelIndexList) nel view. Questa variante
viene utilizzata quando si vuole visualizzare o modificare una serie di
lampioni che sono stati selezionati nel view. Il flag ReadOnly indica se
i dati delle lamps devono essere solo visualizzati (comando Info) o se
devono essere editati.
Il terzo costruttore ` implementato con l’ausilio di un QDataWidgetMap-
e
per. Questa classe permette di “mappare” i dati di un model nei campi di
una widget. Questa funzione permette di scorrere facilmente tutti i record
del database dalla stessa widget, attraverso due pulsanti avanti e indietro e,
all’occorrenza, modificarli al volo.
L’impego di un data mapper ha richiesto per` l’implementazione di un
o
delegate personalizzato, il comboDelegate, che vedremo pi` avanti.adatto che
u
vedremo pi` avanti.
u
I metodi della classe LampPage sono:
• Next()/Previous(): sono due funzioni slot collegati ai pulsanti per scor-
rere tra i record in fase di modifica/visualizzazione delle lamps;
• addNewLamp(): il metodo, invocato dalloslot submit() aggiunge un
nuovo lampione nel database;
• submitEdit(): aggiorna i dati in seguito alla modifica dell’utente;
• uploadImage(): serve a leggere l’immagine in formato binario dal database;
53. 4.3 Database 51
• createComboBoxModel(): questo metodo associa i menu a “discesa”
(combo box) con il contenuto delle tabelle relazionate. L’associazione
per` non ` diretta ma passa per la creazione di un model “intermedio”
o e
( QSortFilterProxyModel) sul quale possiamo agire in modo da ordinare
alfabeticamente le voci, per una lettura pi` semplice.
u
La struttura delle widget, per l’editing delle altre tabelle, ` pressoch` la
e e
stessa. Si possono quindi definire tre metodi comuni, implementati all’inizio
del file:
• createTableView(): riceve come argomento il model di una tabella re-
lazionata, ne istanzia la visualizzazione come elenco e restituisce il
puntatore al view creato;
• addNewItem(): permette di inserire un nuovo record nella tabella il cui
model viene passato come argomento;
• deleteItem(): a differenza della funzione di inserimento, riceve come
argomento l’intero model. Questo perch` il metodo verifica prima
e
che la tabella principale non contenga delle lamps con l’attributo da
eliminare.
Le pages sono costituite da una lista (view ), attraverso la quale scegliere
il record da modificare o eliminare un record, ed uno o pi` campi dove poter
u
inserire i dati dei nuovi record. I pulsanti Add, Save e Delete sono collegati,
mediante il sistema signal/slot, rispettivamente ai seguenti metodi:
• submit(): insieme al metodo comune addNewItem() permette di ag-
giungere nuovi record alla tabella di riferimento;
• save(): salva nel model (e quindi nel database Sql) le modifiche appor-
tate ad un record;
• remove(): elimina dal model (e quindi dal database Sql) il record
selezionato.
Il database Sql ` impostato per avere valori unici. Questo vuol dire che
e
non ` possibile, ad esempio, inserire due vie con lo stesso nome. In questa
e
eventualit`, il metodo che invia le modifiche del model al database, ossia
a
submitAll(), restituirebbe valore false, producendo un messaggio di errore.
54. 4.3 Database 52
Fig. 4.5: Funzionamento di un delegate standard
Fig. 4.6: Delegate standard con proxy model intermedio
Classe ComboDelegate
La classe comboDelegate ` stata scritta per rimpiazzare il delegate
e
standard per il widget data mapper utilizzato nella lampPage.
In Fig. 4.5 ` rappresentata un menu a tendina (combo box) i cui dati
e
sono originati dalla tabella model. Un delegate standard interpreta la scelta
dell’utente, salvando nel model principale non il valore scelto, ma l’indice
corrispondente.
Il problema nasce nel momento in cui decidiamo di “inteporre” un model
intermedio ( proxyModel) con lo scopo di ordinare alfabeticamente le voci nel
menu (Fig. 4.6). Il delegate standard infatti non considera l’id associato alla
voce, bens` salva nel model principale l’indice con il quale la voce compare
ı
nel menu combo, con conseguente inconsistenza dei valori.
Per questo motivo si ` reso necessario reimplementare il delegate nella
e
classe comboDelegate, presente nell’omonimo file. In particolare sono stati
riscritti due metodi fondamentali del delegate:
• setEditorData(): legge l’indice dell’elemento nel proxy model, ricava