! | Данная информация предназначена только только для IT-специалистов по системной интеграции модулей БИОСОФТ-М. (см. Руководства пользователя к программным продуктам) |
Packages/PexLink остается как и раньше заниматься добавлением и просмотром измерений в обследованиях данной модальности.
В отдельный пакет Packages/PexPlugin выносится вся логика, расширяющая функциональность Pex, специфическими функциями, требуемыми для данной модальности.
См. Emix/Packages/PexPlugin где демонстрируются два типа плугина:
Emix для обоих демо показывает полученые вычисленных данных из карточки. В виде экспозированного кеша в первом случае, и простого скалярного значения во втором.
Плугины в Emix/Packages/PexPlugin структурированы так чтобы четко отделить логику, выполняемую в рамках процесса БД Pex и в рамках процесса самплера. Только в частном случае Pili оба процесса могут совпадать. Вся логика плугинов должна работать в любом варианте подключения к БД. Коммуникация между плугинной и самплерной стороной возможна только через официальные интерфейсы PexContact/PexInsert/Pi.
По этому плугины разделены на два Iface класса видимых приложению
"Receiver" может стать слишком узким термином если сторона на PexContact будет не только получать что то из карточки, но пока это по сути. "Receiver" просто инкапсулирует получение полей из карточки. Он относится к PexContact, общается с пакетом PexLink но вынесен из него т.к. не занимается регистрацией измерений.
Плугины подключаются к Pex при инициализации PexInsert для данной модальности. Инициализация оного остается как и раньше в пакете PexLink и вызывает CXxxPluginIface из пакета PexPlugin:
void CEmixPexInsertLinkImpl::OnInitEmixPexInsertLink( ref<CPexInsertConnectionIfaceGp> rPexInsertConnection) { if (rPexInsertConnection->IsPexInsertConnectionAvailable()) { ... x_rPexInsertConnection-> ConnectInsertedModule(... //VL: 2014-06-04 -U2 // Install Picom callback m_rEmixIndividualNormPlugin-> InitEmixIndividualNormPlugin( x_rPexInsertConnection); // Predefine card fields m_rEmixOptimumPlugin-> InitEmixOptimumPlugin( x_rPexInsertConnection); //VL. } }
Как видим инициализаторы плугинов получат все необходимые им связи из rPexInsertConnection.
Плугин EmixIndividualNorm демонстрирует отслеживание добавления новых измерений и запуск новых обследований своим прибором для пересчета своих данных.
Для установки своего колбака на события в Picom используется RegisterPicomUpdateCallback(колбак, очередность):
void CEmixIndividualNormPluginImpl::OnInitEmixIndividualNormPlugin( ref<CPexInsertConnectionIfaceGp> rPexInsertConnection) { rASSERT(... // register our callback m_rEmixPicomUpdate->_x_pEmixIndividualNormPlugin = this; rPexInsertConnection-> RegisterPicomUpdateCallback( m_rEmixPicomUpdate, CPicomUpdateIfaceGp::E_PicomUpdateOrder_CEmixPicomUpdate); }
См. CEmixPicomUpdate где происходит отработка соответствующих событий. Данный объект колбака может быть связан с EmixIndividualNormPluginImpl указателем ptr. Через этот указатель он делегирует выполнение всех вычислений объекту сессии плугина CEmixIndividualNormPluginImpl. Обращаю особое внимание на возможность такого указателя в данном сценарии работы.
Broadcast callbacks с множеством получателей (CMulticallGp) на котором построен PicomUpdateтребует декларации enum константы для каждого класса обработчика. Соответственно нужно добавить такую константу в CPicomUpdateIfaceGp::EPicomUpdateOrder. Не забывать напоминать при интеграции нового плугина!
Другой тип связи с Pex демонстрирует плугин EmixOptimumPlugin. Он не занимается отработкой событий Picom а создает себе особое поле карточки, обвешивая его контекстными колбаками:
void CEmixOptimumPluginImpl::OnInitEmixOptimumPlugin( ref<CPexInsertConnectionIfaceGp> rPexInsertConnection) { rASSERT(... PrepareOptimumButtonCardField( rPexInsertConnection-> x_rPiCardConfig); }
Здесь мы:
Подробнее:
void CEmixOptimumPluginImpl::PrepareOptimumButtonCardField( ref<CPiCardConfigIfaceGp> rPiCardConfig) { // define our main card field str sFieldKey = CEmixOptimumCallback::C_sFieldKeyForEmixOptimum; if not_null( ref<CPiFieldConfigIfaceGp> rPiFieldConfig = rPiCardConfig-> DefinePatientFieldByPlugin( sFieldKey)) { TESTLOG("", "Defining field " + sFieldKey + "\n"); // initialize options rPiFieldConfig-> SetPiFieldLabelForUi( Enru_VL( "Emix Optimum", "Îïòèìóì Emix")); // hide it? rPiFieldConfig-> x_bHiddenPiField = false; // install the callback { // "Button"-field will use this key to lookup card config looking for click-handler key keyClickHandlerCookie = CEmixOptimumCallback::C_keyFieldButtonCallbackCookieForEmixOptimum; // // install special "Button" field customizer plugin from Picom // ref<CPicomFieldInputButtonIfaceGp> rPicomFieldInputButton; // we aren't loaded automatically with Pex, // so the button needs to preload us before we can handle anything rPicomFieldInputButton-> x_sPreloadFieldButtonModule = CProject::GGetGlobalProjectLogo(); // our click handler address in the card field config rPicomFieldInputButton-> x_keyFieldButtonCallbackCookie = keyClickHandlerCookie; // UI { rPicomFieldInputButton-> x_slocFieldButtonText = Enru_VL( "Input or Recalculate", "Ââîä èëè ïåðåñ÷åò") + " //TODO: rename!"; rPicomFieldInputButton-> x_slocFieldButtonTip = //Enru( "TODO: Emix button tooltip"; //"Input or Recalculate", //"Ââîä èëè ïåðåñ÷åò"); } // save field customizer in the card config rPiFieldConfig-> SetPluginAdditionalFieldConfigCallbacks( CPiFieldConfigIfaceGp::C_keyFieldCallbackForMainFieldInputUi, rPicomFieldInputButton); // // install our cookie object for the button handler // // save our callback for field customizer installed above rPiFieldConfig-> SetPluginAdditionalFieldConfigCallbacks( keyClickHandlerCookie, m_rEmixOptimumCallback); } } }
См. CEmixOptimumCallback где происходит отработка нажатия вставленной в поле карточи кнопки. Обрашаю внимание что данных колбак сохраняется и восстанавливается экспозицией, вися в мапе конфига карточки. У него нет возможности после восстановления получить ptr на объект CEmixOptimumPluginImpl. Поэтому объект сессии CEmixOptimumPluginImpl выполняет только инициализацию и потом больше не используется в данном примере.
Данный плугин должен выполнять всю свою работу не располагая никаким глобальным контекстом а только ссылкой ref<CPiFieldValueIfaceGp> на значение карточки для данного пациента для которого нажата кнопка. И через Pi API из него можно выудить всю нужную информацию о пациенте.
CEmixIndividualNormPluginImpl::CalcEmixIndividualNorm( ref<CPiPatientIfaceGp> rPiPatient)
Обращаю внимание что данные измерений доступны плугину только для чтения. Категорически запрещается пытаться их изменять даже если через запреты SEMIPUBLIC(_picom_) просочились Set-методы!
С полем карточки можно ассоциировать два значения.
делается DefinePatientFieldByPlugin() (см. примеры в Emix)
демонстрируется с использованием SetPiFieldValueAsStr()
см. SetPluginAdditionalFieldValueCache()