/******************************************************************************* * Copyright (c) 2005-2010, G. Weirich and Elexis * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * G. Weirich - initial implementation * *******************************************************************************/ package ch.elexis.core.ui.laboratory.views; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CTabFolder; import org.eclipse.swt.custom.CTabItem; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.ui.IActionBars; import org.eclipse.ui.ISaveablePart2; import org.eclipse.ui.part.ViewPart; import org.jdom.Document; import org.jdom.Element; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; import ch.elexis.core.data.events.ElexisEvent; import ch.elexis.core.data.events.ElexisEventDispatcher; import ch.elexis.core.data.events.ElexisEventListener; import ch.elexis.core.data.util.Extensions; import ch.elexis.core.ui.Hub; import ch.elexis.core.ui.UiDesk; import ch.elexis.core.ui.actions.GlobalActions; import ch.elexis.core.ui.constants.ExtensionPointConstantsUi; import ch.elexis.core.ui.events.ElexisUiEventListenerImpl; import ch.elexis.core.ui.icons.Images; import ch.elexis.core.ui.laboratory.controls.LaborOrdersComposite; import ch.elexis.core.ui.laboratory.controls.LaborResultsComposite; import ch.elexis.core.ui.laboratory.dialogs.LaborVerordnungDialog; import ch.elexis.core.ui.util.Importer; import ch.elexis.core.ui.util.Log; import ch.elexis.core.ui.util.SWTHelper; import ch.elexis.core.ui.util.ViewMenus; import ch.elexis.data.LabItem; import ch.elexis.data.LabOrder; import ch.elexis.data.LabResult; import ch.elexis.data.Patient; import ch.elexis.data.Person; import ch.rgw.tools.ExHandler; import ch.rgw.tools.TimeTool; /** * Anzeige von Laboritems und Anzeige und Eingabemöglichkeit von Laborwerten. * * Der Algorithmus geht so: Zuerst werden alle Laboritems eingesammelt und gemäss ihren Gruppen und * Prioritäten sortiert (nur beim create) Beim Einlesen eines neuen Patienten werden zunächst alle * Daten gesammelt, an denen für diesen Patienten Laborwerte vorliegen. Diese werden nach Alter * sortiert und mit den jeweiligen Laborwerten zusammengefasst. Jeweils NUMCOLUMNS Daten werden auf * einer Anzeigeseite angezeigt. Der Anwender kann auf den Seiten blättern, aber es werden alle * Laborwerte des aktuellen Patienten im Speicher gehalten. * * @author gerry */ public class LaborView extends ViewPart implements ISaveablePart2 { public static final String ID = "ch.elexis.Labor"; //$NON-NLS-1$ private static Log log = Log.get("LaborView"); //$NON-NLS-1$ private CTabFolder tabFolder; private LaborResultsComposite resultsComposite; private LaborOrdersComposite ordersComposite; private Action fwdAction, backAction, printAction, importAction, xmlAction, newAction, newColumnAction, refreshAction, expandAllAction, collapseAllAction; private ViewMenus menu; private ElexisUiEventListenerImpl eeli_pat = new ElexisUiEventListenerImpl(Patient.class) { @Override public void runInUi(ElexisEvent ev){ resultsComposite.selectPatient((Patient) ev.getObject()); ordersComposite.selectPatient((Patient) ev.getObject()); } }; private ElexisEventListener eeli_labitem = new ElexisEventListener() { private final ElexisEvent eetmpl = new ElexisEvent(null, LabItem.class, ElexisEvent.EVENT_RELOAD); @Override public ElexisEvent getElexisEventFilter(){ return eetmpl; } @Override public void catchElexisEvent(ElexisEvent ev){ UiDesk.getDisplay().asyncExec(new Runnable() { @Override public void run(){ resultsComposite.reload(); } }); } }; private ElexisEventListener eeli_labresult = new ElexisEventListener() { private final ElexisEvent eetmpl = new ElexisEvent(null, LabResult.class, ElexisEvent.EVENT_RELOAD); @Override public ElexisEvent getElexisEventFilter(){ return eetmpl; } @Override public void catchElexisEvent(ElexisEvent ev){ UiDesk.getDisplay().asyncExec(new Runnable() { @Override public void run(){ resultsComposite.reload(); ordersComposite.reload(); } }); } }; private ElexisEventListener eeli_laborder = new ElexisEventListener() { private final ElexisEvent eetmpl = new ElexisEvent(null, LabOrder.class, ElexisEvent.EVENT_RELOAD); @Override public ElexisEvent getElexisEventFilter(){ return eetmpl; } @Override public void catchElexisEvent(ElexisEvent ev){ UiDesk.getDisplay().asyncExec(new Runnable() { @Override public void run(){ ordersComposite.reload(); } }); } }; @Override public void createPartControl(final Composite parent){ setTitleImage(Images.IMG_VIEW_LABORATORY.getImage()); tabFolder = new CTabFolder(parent, SWT.TOP); tabFolder.setLayout(new FillLayout()); final CTabItem resultsTabItem = new CTabItem(tabFolder, SWT.NULL); resultsTabItem.setText("Resultate"); resultsComposite = new LaborResultsComposite(tabFolder, SWT.NONE); resultsTabItem.setControl(resultsComposite); final CTabItem ordersTabItem = new CTabItem(tabFolder, SWT.NULL); ordersTabItem.setText("Verordnungen"); ordersComposite = new LaborOrdersComposite(tabFolder, SWT.NONE); ordersTabItem.setControl(ordersComposite); tabFolder.setSelection(0); tabFolder.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e){ resultsComposite.reload(); ordersComposite.reload(); } }); makeActions(); menu = new ViewMenus(getViewSite()); menu.createMenu(newAction, backAction, fwdAction, printAction, importAction, xmlAction); // Orders final LaborOrderPulldownMenuCreator menuCreator = new LaborOrderPulldownMenuCreator(parent.getShell()); if (menuCreator.getSelected() != null) { IAction dropDownAction = menuCreator.getAction(); IActionBars actionBars = getViewSite().getActionBars(); IToolBarManager toolbar = actionBars.getToolBarManager(); toolbar.add(dropDownAction); // Set data dropDownAction.setText(menuCreator.getSelected().getText()); dropDownAction.setToolTipText(menuCreator.getSelected().getToolTipText()); dropDownAction.setImageDescriptor(menuCreator.getSelected().getImageDescriptor()); } // Importers IToolBarManager tm = getViewSite().getActionBars().getToolBarManager(); List<IAction> importers = Extensions.getClasses( Extensions.getExtensions(ExtensionPointConstantsUi.LABORDATENIMPORT), "ToolbarAction", //$NON-NLS-1$ //$NON-NLS-2$ false); for (IAction ac : importers) { tm.add(ac); } if (importers.size() > 0) { tm.add(new Separator()); } tm.add(refreshAction); tm.add(newColumnAction); tm.add(newAction); tm.add(backAction); tm.add(fwdAction); tm.add(expandAllAction); tm.add(collapseAllAction); tm.add(printAction); // register event listeners ElexisEventDispatcher.getInstance().addListeners(eeli_labitem, eeli_laborder, eeli_labresult, eeli_pat); Patient act = (Patient) ElexisEventDispatcher.getSelected(Patient.class); if ((act != null && act != resultsComposite.getPatient())) { resultsComposite.selectPatient(act); } } @Override public void dispose(){ super.dispose(); ElexisEventDispatcher.getInstance().removeListeners(eeli_labitem, eeli_laborder, eeli_labresult, eeli_pat); } @Override public void setFocus(){ if (resultsComposite.isVisible()) { resultsComposite.setFocus(); } else if (ordersComposite.isVisible()) { ordersComposite.setFocus(); } } private void makeActions(){ fwdAction = new Action(Messages.LaborView_nextPage) { @Override public void run(){ resultsComposite.setColumnOffset(resultsComposite.getColumnOffset() + 1); resultsComposite.reload(); tabFolder.setSelection(0); } }; backAction = new Action(Messages.LaborView_prevPage) { @Override public void run(){ resultsComposite.setColumnOffset(resultsComposite.getColumnOffset() - 1); resultsComposite.reload(); tabFolder.setSelection(0); } }; printAction = new Action(Messages.LaborView_print) { @Override public void run(){ try { LaborblattView lb = (LaborblattView) getViewSite().getPage().showView(LaborblattView.ID); Patient pat = ElexisEventDispatcher.getSelectedPatient(); lb.createLaborblatt(pat, resultsComposite.getPrintHeaders(), resultsComposite.getPrintRows(), resultsComposite.getSkipIndex()); } catch (Exception ex) { ExHandler.handle(ex); } } }; importAction = new Action(Messages.LaborView_import) { { setImageDescriptor(Images.IMG_IMPORT.getImageDescriptor()); setToolTipText(Messages.LaborView_importToolTip); } @Override public void run(){ Importer imp = new Importer(getViewSite().getShell(), ExtensionPointConstantsUi.LABORDATENIMPORT); //$NON-NLS-1$ imp.create(); imp.setMessage(Messages.LaborView_selectDataSource); imp.getShell().setText(Messages.LaborView_labImporterCaption); imp.setTitle(Messages.LaborView_labImporterText); imp.open(); } }; xmlAction = new Action(Messages.LaborView_xmlExport) { @Override public void run(){ Document doc = makeXML(); if (doc != null) { FileDialog fsel = new FileDialog(Hub.plugin.getWorkbench().getActiveWorkbenchWindow() .getShell()); String fname = fsel.open(); if (fname != null) { try { FileOutputStream fout = new FileOutputStream(fname); OutputStreamWriter cout = new OutputStreamWriter(fout, "UTF-8"); //$NON-NLS-1$ XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat()); xout.output(doc, cout); cout.close(); fout.close(); } catch (Exception ex) { ExHandler.handle(ex); SWTHelper.alert(Messages.LaborView_ErrorCaption, Messages.LaborView_couldntwrite + fname); } } } } }; newColumnAction = new Action(Messages.LaborView_newDate) { @Override public void run(){ tabFolder.setSelection(0); resultsComposite.toggleNewColumn(); } }; newAction = new Action(Messages.LaborView_newDate) { @Override public void run(){ Patient patient = ElexisEventDispatcher.getSelectedPatient(); if (patient == null) { return; } TimeTool date = new TimeTool(); LaborVerordnungDialog dialog = new LaborVerordnungDialog(getSite().getShell(), patient, date); if (dialog.open() == LaborVerordnungDialog.OK) { tabFolder.setSelection(1); } } }; refreshAction = new Action(Messages.LaborView_Refresh) { @Override public void run(){ resultsComposite.reload(); ordersComposite.reload(); } }; expandAllAction = new Action("Expand All") { @Override public void run(){ if (tabFolder.getSelectionIndex() == 0) { resultsComposite.expandAll(); } } @Override public ImageDescriptor getImageDescriptor(){ return Images.IMG_ARROWDOWN.getImageDescriptor(); } }; collapseAllAction = new Action("Collapse All") { @Override public void run(){ if (tabFolder.getSelectionIndex() == 0) { resultsComposite.collapseAll(); } } @Override public ImageDescriptor getImageDescriptor(){ return Images.IMG_ARROWUP.getImageDescriptor(); } }; newColumnAction.setImageDescriptor(Images.IMG_NEW.getImageDescriptor()); newAction.setImageDescriptor(Images.IMG_ADDITEM.getImageDescriptor()); fwdAction.setImageDescriptor(Images.IMG_NEXT.getImageDescriptor()); backAction.setImageDescriptor(Images.IMG_PREVIOUS.getImageDescriptor()); printAction.setImageDescriptor(Images.IMG_PRINTER.getImageDescriptor()); xmlAction.setImageDescriptor(Images.IMG_EXPORT.getImageDescriptor()); refreshAction.setImageDescriptor(Images.IMG_REFRESH.getImageDescriptor()); } public Document makeXML(){ Document doc = null; try { doc = new Document(); Element r = new Element("Laborblatt"); //$NON-NLS-1$ r.setAttribute("Erstellt", new TimeTool() //$NON-NLS-1$ .toString(TimeTool.FULL_GER)); Patient actpat = ElexisEventDispatcher.getSelectedPatient(); if (actpat == null) { return doc; } r.setAttribute("Patient", actpat.getLabel()); //$NON-NLS-1$ doc.setRootElement(r); Element Daten = new Element("Daten"); //$NON-NLS-1$ r.setAttribute("Patient", actpat.getLabel()); //$NON-NLS-1$ HashMap<String, HashMap<String, HashMap<String, List<LabResult>>>> groupedResults = LabResult.getGrouped(actpat); List<String> dates = getDates(groupedResults); for (String d : dates) { Element dat = new Element("Datum"); //$NON-NLS-1$ dat.setAttribute("Tag", d); //$NON-NLS-1$ Daten.addContent(dat); } r.addContent(Daten); ArrayList<String> groupNames = new ArrayList<String>(); groupNames.addAll(groupedResults.keySet()); for (String g : groupNames) { Element eGroup = new Element("Gruppe"); //$NON-NLS-1$ eGroup.setAttribute("Name", g); //$NON-NLS-1$ HashMap<String, HashMap<String, List<LabResult>>> itemMap = groupedResults.get(g); List<LabItem> items = getItems(itemMap); if (items == null) { log.log("Ungültige Gruppe " + g, Log.WARNINGS); //$NON-NLS-1$ continue; } if (items.size() == 0) { continue; } for (LabItem it : items) { Element eItem = new Element("Parameter"); //$NON-NLS-1$ eItem.setAttribute("Name", it.getName()); //$NON-NLS-1$ eItem.setAttribute("Kürzel", it.getKuerzel()); //$NON-NLS-1$ eItem.setAttribute("Einheit", it.getEinheit()); //$NON-NLS-1$ HashMap<String, List<LabResult>> resultsPerDate = itemMap.get(it.getShortLabel()); Set<String> resultDates = resultsPerDate.keySet(); for (String date : resultDates) { List<LabResult> results = resultsPerDate.get(date); Element eResult = new Element("Resultat"); //$NON-NLS-1$ eResult.setAttribute("Datum", date); //$NON-NLS-1$ eItem.addContent(eResult); for (LabResult lr : results) { eResult.addContent(lr.getResult()); } Element ref = new Element("Referenz"); //$NON-NLS-1$ ref.setAttribute(Person.MALE, it.get("RefMann")); //$NON-NLS-1$ //$NON-NLS-2$ ref.setAttribute(Person.FEMALE, it.get("RefFrauOrTx")); //$NON-NLS-1$ //$NON-NLS-2$ eItem.addContent(ref); } eGroup.addContent(eItem); } if (eGroup.getContentSize() != 0) { r.addContent(eGroup); } } } catch (Exception ex) { ExHandler.handle(ex); } return doc; } private List<LabItem> getItems(HashMap<String, HashMap<String, List<LabResult>>> itemMap){ Set<String> keys = itemMap.keySet(); ArrayList<LabItem> ret = new ArrayList<LabItem>(); for (String string : keys) { Collection<List<LabResult>> values = itemMap.get(string).values(); if (!values.isEmpty()) { Iterator<List<LabResult>> iter = values.iterator(); List<LabResult> first = iter.next(); while (first.isEmpty() && iter.hasNext()) { first = iter.next(); } ret.add((LabItem) first.get(0).getItem()); } } return ret; } public List<String> getDates( HashMap<String, HashMap<String, HashMap<String, List<LabResult>>>> map){ ArrayList<String> ret = new ArrayList<String>(); HashSet<String> dateStrings = new HashSet<String>(); for (String group : map.keySet()) { HashMap<String, HashMap<String, List<LabResult>>> itemMap = map.get(group); for (String item : itemMap.keySet()) { dateStrings.addAll(itemMap.get(item).keySet()); } } ret.addAll(dateStrings); Collections.sort(ret); return ret; } public void activation(final boolean mode){} /*********************************************************************************************** * Die folgenden 6 Methoden implementieren das Interface ISaveablePart2 Wir benötigen das * Interface nur, um das Schliessen einer View zu verhindern, wenn die Perspektive fixiert ist. * Gibt es da keine einfachere Methode? */ @Override public int promptToSaveOnClose(){ return GlobalActions.fixLayoutAction.isChecked() ? ISaveablePart2.CANCEL : ISaveablePart2.NO; } @Override public void doSave(final IProgressMonitor monitor){ /* leer */ } @Override public void doSaveAs(){ /* leer */ } @Override public boolean isDirty(){ return true; } @Override public boolean isSaveAsAllowed(){ return false; } @Override public boolean isSaveOnCloseNeeded(){ return true; } public void reloadContents(final Class clazz){ if (clazz.equals(LabItem.class)) { } } }