Creare una nuova classe
Attualmente, il codice della feature di autocompletamento è incluso all'interno della classe UserModel.
L'interazione tra questi elementi, tuttavia, è limitata a due sole funzioni:
- Passare gli username al codice di autocompletamento tramite la Qlist Users;
- Comunicare con il codice QML tramite le chiamate alle nuove proprietà (Q_PROPRIETY).
Troppo poco per ammassare tanto codice in un'unica classe.
Proviamo perciò a riscrivere la patch, facendo riferimento al branch in versione 2 del nostro fork.
Anziché acquisire gli username dalla classe UserModel, è meglio ricaricarli direttamente attraverso una chiamata a getpwent.
La comunicazione con il codice QML, invece, deve essere impostata nella classe GreeterApp, che inizializza l'intero programma.
Sono in tutto 5 righe di codice:
$ grep utoCompletion GreeterApp.h GreeterApp.cpp GreeterApp.h: class AutoCompletion; GreeterApp.h: AutoCompletion *m_autoCompletion { nullptr }; GreeterApp.cpp:#include "AutoCompletion.h" GreeterApp.cpp: m_autoCompletion = new AutoCompletion(); GreeterApp.cpp: view->rootContext()->setContextProperty(QStringLiteral("autoCompletion"), m_autoCompletion);
Interessante, in particolare, l'ultima riga. Fa in modo che il codice QML riconosca la chiave autoCompletion' (con la a minuscola) per acccedere alle proprietà specifiche della nuova classe.
Una classe deve contenere:
- Le Q_PROPERTY di interazione; - Un costruttore di inizializzazione; - Le proprie funzioni specifiche.
Nel nostro caso le proprietà sono le stesse già descritte in precedenza: auC,head e tail.
Il costruttore replica quello della classe Usermodel, ma ha un contenuto vuoto:
AutoCompletion::AutoCompletion(QObject *parent) : QAbstractListModel(parent), d(new AutoCompletionPrivate()) {}
La sua funzione è soltanto quella di preparare un puntatore alla classe AutoCompletion di tipo QAbstractListModel, affinché (in futuro), l'autocompletamento si possa far carico di costruire dinamicamente la lista utenti, sostituendo l'implementazione statica della classe UserModel.
L'inizializzazione reale della classe AutoCompletion sarà invece delegata alla funzione initAutoCompletion e sarà invocata esclusivamente ai layout che ne richiedono esplicitamente l'uso.
Bisogna osservare che impostare una classe come QAbstractListModel impone l'introduzione di alcune funzioni obbligatorie:
- int AutoCompletion::rowCount(...) - QVariant AutoCompletion::data() - QHash<int, QByteArray> AutoCompletion::roleNames() (non obbligatoria, ma mantenuta per analogia)
Queste funzioni sono state implementate in analogia con la versione corrispondente di UserModel.
Riassumendo, la gestione della classe si articola in tre fasi distinte:
- Impostazione del dialogo con QML, gestito nella classe di apertura GreeterApp, tramite una chiamata al costruttore vuoto AutoCompletion(...);
- Inizializzazione della ricerca, su richiesta QML, tramite la proprieà autoCompletion.initAutoCompletion, che carica i nomi utente con getpwent;
- Dialogo dinamico con il QML tramite le proprietà autoCompletion.head e autoCompletion.tail, identiche alle verioni già descritte in precedenza.