CLB_messenger
La classe appartiene al namespace CLB::Messaging; il namespace CLB, contenuto nella dll CLB_000 è destinato a contenere tutte le classi di nuova generazione di Colibri, dalla versione 8 in poi.
CLB_messenger permette la messaggistica bidirezionale fra oggetti; introdotta dalla data 20 febb 2019, ha lo scopo di facilitare la comunicazione fra oggetti.
Il paradigma è molto semplice:
- Tutte le classi che vengono connesse sono derivate da CLB_messenger; in pratica, attraverso la dichiarazione public CLB_messenger la classe eredita l’interfaccia che permetterà la trasmissione diretta di comandi e parametri (vedremo come)
- Sono definite funzioni send(..) e send_to_obj(..) per la trasmissione di un messaggio ad oggetto di cui si conosce il nome globale, o nel secondo caso del quale si conosce l’indirizzo (puntatore).
- Viene riscritta per ogni classe derivata la funzione virtuale slot_messenger(..) che costituisce il parser dei comandi ricevuti; è compito di questa funzione filtrare i comandi secondo le specifiche costruttive (vederemo che è possibile interrogare le classi per ottenere una lista delle specifiche di comando, più o meno come avviene con i servizi web..)
- Se una istanza CLB_messenger A viene registrata attraverso la funzione CLB_messenger::regs(..) di un’altra istanza B di CLB_messenger, essa riceverà in slot_messenger(..) tutte le notifiche dei comandi lanciati dall’oggetto B, fino ad una eventuale chiamata B->unregs(A);
- Tutte le istanze allocate delle classi di interfaccia CLB_messenger vengono automaticamente registrate in una lista di accesso, fino alla loro distruzione; questo permette un accesso all’oggetto attraverso il nome proprio, un identificatore univoco dell’istanza; descriveremo di seguito come gestire questa eventualità.
Nota: In pratica, una classe derivata da CLB_messenger potrebbe solo possedere una funzione slot_messenger(..) per potere ricevere comandi da un qualunque oggetto creato nel framework..
Questo è il codice di dichiarazione della classe:
class AFX_EXT_CLASS CLB_messenger { public: bool regs(CLB_messenger *robj); bool unregs(CLB_messenger *robj); bool registered(CLB_messenger *robj); CLB_messenger(); ~CLB_messenger(); virtual bool slot_messenger(_received_data); bool send(__arg_value cmd, ...); bool send_to_obj(CLB_messenger *receiver, __arg_value pars, ...); __use_private_struct };
bool regs(CLB_messenger *robj)
registrazione di una classe come oggetto ricevente. Questa funzione permette di registrare l’oggetto robj come ricevente automatico della messaggistica (comandi) della classe. In pratica tutti i comandi mandati attraverso la funzione Send() del sender saranno ricevuti dagli oggetti
registrati. E’ possibile registrare un numero qualunque di istanze receiver, e tutti questi oggetti potranno mandare anche messaggi all’oggetto sul quale sono stati registrati.
bool unregs(CLB_messenger *robj)
rimozione dell’oggetto registrato. L‘oggetto viene comunque automaticamente rimosso quando distrutta la classe, e l’operazione è fatta dal distruttore di CLB_messenger dal quale deriva. Dopo la sua de-registrazione l’oggetto non riceverà più comandi dalla classe alla quale era collegato cod la funzione regs.
bool registered(CLB_messenger *robj)
Testa che la istanza robj sia stata registrata nella classe; in questo caso rimanda true;
bool send(__arg_value cmd, …)
Manda un comando e parametri relativi a tutti gli oggetti registrati come receiver attraverso la funzione regs; l’ultimo elemento della var_list passata deve essere necessariamente _$end:
bool send_to_obj(CLB_messenger *receiver, __arg_value pars, …)
manda un comando e parametri ad uno specifico oggetto receiver. l’ultimo elemento della var_list passata deve essere necessariamente _$end;
in questo caso non è necessario che receiver sia stato registrato basta sia un puntatore a un CLB_messenger (vedi l’esempio di codice precedente relativo allo slot di DOCK_document_navigator)
virtual bool slot_messenger(_received_data)
Questa funzione deve essere riscritta per ogni classe derivata da CLB_messenger, perchè corrisponde al parser dei comandi ricevuti. Strutturalmente non è molto diverso dalla definizione di uno slot di ricezione messaggi di OPERATION_CALL prima descritto per DOCK_document_navigator).
Si riporta ad esempio la funzione scritta per la classe Widget_plotter
bool Widget_plotter::slot_messenger(_received_data) { __getstr __is_request(_$get,_$selected, _$curve) { __pop_p(cv, CURVE); _$str->edit->get_selected_curve(cv); } return true; }
come parametro passato alla funzione, in conformità con la dichiarazione della stessa, c’è sempre la macro _received_data :
#define _received_data test_request &_requ_
questo è un modo per rendere immediatamente utilizzabili le macro __is_request (incontrata prima descrivendo la classe test_request) e __pop_v , una macro equivalente alla __pop_param
nel nostro esempio _$get,_$selected, _$curve
è il comando che richiede un puntatore ad un oggetto CURVE contenuto nella classe; l’oggetto è trasferito nel parametro CURVE *cv estratto dallo stack dei comandi e parametri con __pop_p. La funzione chiamante riceverà questa informazione, come si vede nel codice che segue e che ha effettuato la chiamata..
// funzione di ricezione dei messaggi da CLB_messenger bool slot_messenger(_received_data) { if (!_$str->layout) return false; __is_sender(w_plot) { __is_request(_$get, _$image, _$background) { __pop_p(img, IMAGE*); Layer_color *mrc = _$str->layout->Get_selected_layer(); if (mrc) *img=mrc->get_background_image(); return true; } __is_request(_$modified, _$function) { Layer_color *mrc = _$str->layout->Get_selected_layer(); if (mrc) { CURVE *curva = mrc->get_curva(); __send_cmd_to_obj(w_plot, _$get, _$selected, _$curve, curva); // estrae la curva modificata mrc->calculate_layer_image(); // ricalcola lìimmagine di propagazione igrp->calculate_prop_image(); _paint_result(); } } } return true; }
il codice della classe cui appartiene la funzione, ha ricevuto un messaggio che analizza e decide quali azioni compiere: __is_sender(w_plot) è una macro che controlla se il sender del comando è w_plot , già noto alla classe ovviamente, in questo caso se ha ricevuto il comando $modified, _$function decide, fra le altre cose, di richiedere la curva per usarla internamente; possiamo osservare che il puntatore curva è passato, come già spiegato, quale parametro nel comando.