/* May 2013: Niklaus Giger various fixes * Date displays year with 2 digits * Comments shorter than 15 characters are shown inline, e.g. 'negative' */ package org.iatrix.messwerte.views; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ColumnViewerEditor; import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; import org.eclipse.jface.viewers.ComboViewer; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.TableViewerEditor; import org.eclipse.jface.viewers.TableViewerFocusCellManager; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.ui.IActionBars; import org.eclipse.ui.ISaveablePart2; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.ViewPart; import org.iatrix.messwerte.Constants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.elexis.core.data.activator.CoreHub; 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.events.Heartbeat.HeartListener; import ch.elexis.core.model.LabResultConstants; import ch.elexis.core.types.LabItemTyp; import ch.elexis.core.ui.UiDesk; import ch.elexis.core.ui.actions.GlobalActions; import ch.elexis.core.ui.actions.GlobalEventDispatcher; import ch.elexis.core.ui.actions.IActivationListener; import ch.elexis.core.ui.dialogs.DateSelectorDialog; import ch.elexis.core.ui.dialogs.DisplayTextDialog; import ch.elexis.core.ui.icons.Images; import ch.elexis.core.ui.util.SWTHelper; import ch.elexis.data.LabGroup; import ch.elexis.data.LabItem; import ch.elexis.data.LabResult; import ch.elexis.data.Labor; import ch.elexis.data.Patient; import ch.elexis.data.PersistentObject; import ch.elexis.data.Person; import ch.elexis.data.Query; import ch.rgw.tools.ExHandler; import ch.rgw.tools.StringTool; import ch.rgw.tools.TimeTool; /* * TODO: implement HeartListener (register listeners) */ public class MesswerteView extends ViewPart implements IActivationListener, ISaveablePart2, HeartListener, ElexisEventListener { public static final String ID = "org.iatrix.messwerte.views.MesswerteView"; protected static Logger log = LoggerFactory.getLogger(ID); /** * Combo item for showing all lab groups */ private static final String GROUPS_ALL = "Alle Resultate"; /** * Combo item for showing the praxis lab items */ private static final String GROUPS_PRAXIS = "Praxislabor"; private static final String FEMININ = Person.FEMALE; /** * Number of columns shown per page */ private static int columnsPerPage; /** * index of the parameter column */ private static final int PARAMETER_INDEX = 0; /** * index of the reference column */ private static final int REF_INDEX = 1; /** * Offset of the first date column */ private static final int DATES_OFFSET = 2; private static final int COLUMN_NAME_DEFAULT_WITH = 200; private static final int COLUMN_REF_DEFAULT_WITH = 110; private static final int COLUMN_DATE_DEFAULT_WITH = 110; private static final int COLUMN_DATE_INITIAL_MIN_WIDTH = 50; private Label pagesLabel; private TableViewer viewer; private TableViewerColumn tableNameColumn; private TableViewerColumn tableRefColumn; private TableViewerColumn[] tableDateColumns; private TableDate[] tableDates; private TableViewerFocusCellManager focusCellManager; /** * List of dates there are values of */ private List<TimeTool> availableDates = new ArrayList<TimeTool>(); /** * List of dates we have columns for */ private List<DateColumn> dateColumns = new ArrayList<DateColumn>(); /** * contains the actual TableDate Values */ private List<TableDate> dateColumnsExpanded = new ArrayList<TableDate>(); private Action newDateAction; private Action fwdAction; private Action backAction; private Action pathologicAction; private ComboViewer laborGroupsViewer; private List<BaseLabGroupElement> labGroupElements = new ArrayList<BaseLabGroupElement>(); private Patient actPatient = null; private int currentPage = 0; private int lastPage = 0; private List<LabRow> viewerRows = new ArrayList<LabRow>(); /** * configured own labors */ private List<Labor> ownLabors = new ArrayList<Labor>(); /* * TODO The following two methods actually belong to ch.elexis.data.LabResult */ private static final String LABORWRTE_TABLENAME = "LABORWERTE"; /** * Get all dates having lab results for the given patient. The dates are sorted in ascending * order. * * @param patient * the patient to get the available dates for * @return the dates having lab results, sorted in ascending order */ public static List<TimeTool> getAvailableDates(Patient patient){ List<TimeTool> dates = new ArrayList<TimeTool>(); String sql = "SELECT Datum FROM " + LABORWRTE_TABLENAME + " WHERE PatientID = ?" + " GROUP BY Datum" + " ORDER BY Datum"; try { PreparedStatement ps = PersistentObject.getConnection().prepareStatement(sql); if (ps != null) { ps.setString(1, patient.getId()); if (ps.execute()) { ResultSet rs = ps.getResultSet(); while (rs.next()) { String date = rs.getString(1); dates.add(new TimeTool(date)); } } } } catch (SQLException ex) { ExHandler.handle(ex); log.error("Fehler beim Ausführen von " + sql); } log.debug("getAvailableDates: return " + dates.size() + " dates for " + patient.getPersonalia()); return dates; } /** * Get all dates having lab results for the given patient, restricted to items given in * labItems. The dates are sorted in ascending order. * * @param patient * the patient to get the available dates for * @return the dates having lab results, sorted in ascending order */ public static List<TimeTool> getAvailableDatesOfGroup(Patient patient, List<LabItem> labItems){ List<TimeTool> dates = new ArrayList<TimeTool>(); String sql = "SELECT Datum, ItemID FROM " + LABORWRTE_TABLENAME + " WHERE PatientID = ?" + " GROUP BY Datum, ItemID" + " ORDER BY Datum"; try { // temporary list for avoiding double values List<String> dateStrings = new ArrayList<String>(); PreparedStatement ps = PersistentObject.getConnection().prepareStatement(sql); if (ps != null) { ps.setString(1, patient.getId()); if (ps.execute()) { ResultSet rs = ps.getResultSet(); while (rs.next()) { String date = rs.getString(1); String itemId = rs.getString(2); if (!dateStrings.contains(date)) { for (LabItem labItem : labItems) { if (itemId.equals(labItem.getId())) { // remember this date to avoid duplicates dateStrings.add(date); // add this date to the returned dates dates.add(new TimeTool(date)); // don't continue with further LabItems break; } } } } } } } catch (SQLException ex) { ExHandler.handle(ex); log.error("Fehler beim Ausführen von " + sql); } log.debug("getAvailableDatesOfGroup: return " + dates.size() + " for " + patient.getPersonalia()); return dates; } /** * Get all LabItems the given patient has lab results for. * * @param patient * the patient to get available lab items for * @return all available lab items for the given patient. not ordered. */ public static List<LabItem> getAvailableItems(Patient patient){ List<LabItem> items = new ArrayList<LabItem>(); String sql = "SELECT ItemID FROM " + LABORWRTE_TABLENAME + " WHERE PatientID = ?" + " GROUP BY ItemID"; try { PreparedStatement ps = PersistentObject.getConnection().prepareStatement(sql); if (ps != null) { ps.setString(1, patient.getId()); if (ps.execute()) { ResultSet rs = ps.getResultSet(); while (rs.next()) { String itemId = rs.getString(1); LabItem item = LabItem.load(itemId); if (item != null) { items.add(item); } } } } } catch (SQLException ex) { ExHandler.handle(ex); log.error("Fehler beim Ausführen von " + sql); } log.debug("getAvailableItems: return " + items.size() + " items for " + patient.getPersonalia()); return items; } /* * The content provider class is responsible for providing objects to the view. It can wrap * existing objects in adapters or simply return objects as-is. These objects may be sensitive * to the current input of the view, or ignore it and always show the same content (like Task * List, for example). */ class ViewContentProvider implements IStructuredContentProvider { public void inputChanged(Viewer v, Object oldInput, Object newInput){} public void dispose(){} public Object[] getElements(Object parent){ return viewerRows.toArray(); } } /* * Used by ViewLabelProvider */ private static Font boldFont = null; class ViewLabelProvider extends ColumnLabelProvider { private int columnIndex; ViewLabelProvider(int columnIndex){ super(); this.columnIndex = columnIndex; } public String getText(Object element){ return getColumnText(element, columnIndex); } public Font getFont(Object element){ return getFont(element, columnIndex); } public Color getForeground(Object element){ return getForeground(element, columnIndex); } public Color getBackground(Object element){ return null; } public String getColumnText(Object obj, int index){ String text = ""; if (obj instanceof LabRowGroup) { if (index == 0) { LabRowGroup labRowGroup = (LabRowGroup) obj; text = labRowGroup.group.groupName; int spaceIndex = text.indexOf(" "); if (spaceIndex >= 0) { text = text.substring(spaceIndex + 1); } } } else if (obj instanceof LabRowValues) { LabRowValues row = (LabRowValues) obj; if (index == 0) { text = row.labItem.getShortLabel(); } else if (index == 1) { if (actPatient != null) { if (actPatient.getGeschlecht().equals(FEMININ)) { text = row.labItem.getRefW(); } else { text = row.labItem.getRefM(); } } } else { // index >= DATES_OFFSET: date int datesIndex = index - DATES_OFFSET; TableDate tableDate = tableDates[datesIndex]; if (tableDate != null) { String date = tableDate.date; int valueIndex = tableDate.index; if (!StringTool.isNothing(date)) { List<LabResult> values = row.results.get(date); // check whether the requested value exists if (values != null && values.size() > valueIndex) { StringBuffer sb = new StringBuffer(); boolean isPathologic = false; LabResult labResult = values.get(valueIndex); sb.append(labResult.getResult()); if (labResult.isFlag(LabResultConstants.PATHOLOGIC)) { isPathologic = true; } if (isPathologic && SWT.getPlatform().equals("gtk")) { sb.insert(0, "*"); } text = sb.toString(); // Länge 15 ist Wunsch von Peter Schönbucher. // https://redmine.medelexis.ch/issues/491 if (text.equalsIgnoreCase("text") && labResult.getComment().length() <= 15) { text = labResult.getComment(); } } } } } } return text; } public Image getColumnImage(Object obj, int index){ return null; } public Color getForeground(Object element, int columnIndex){ if (columnIndex >= DATES_OFFSET) { if (element instanceof LabRowValues) { LabRowValues row = (LabRowValues) element; // index >= DATES_OFFSET: date int datesIndex = columnIndex - DATES_OFFSET; TableDate tableDate = tableDates[datesIndex]; if (tableDate != null) { String date = tableDate.date; int valueIndex = tableDate.index; if (!StringTool.isNothing(date)) { List<LabResult> values = row.results.get(date); if (values != null && values.size() > valueIndex) { boolean isPathologic = false; boolean hasComment = false; LabResult labResult = values.get(valueIndex); if (labResult.isFlag(LabResultConstants.PATHOLOGIC)) { isPathologic = true; } if (!StringTool.isNothing(labResult.getComment())) { hasComment = true; } if (isPathologic) { return viewer.getTable().getDisplay() .getSystemColor(SWT.COLOR_RED); } else if (hasComment) { return viewer.getTable().getDisplay() .getSystemColor(SWT.COLOR_BLUE); } } } } } } // default color return null; } public Color getBackground(Object element, int columnIndex){ // default color return null; } public Font getFont(Object element, int columnIndex){ if (element instanceof LabRowGroup) { if (boldFont == null) { Font defaultFont = viewer.getTable().getFont(); FontData defaultFontData = defaultFont.getFontData()[0]; boldFont = new Font(defaultFont.getDevice(), defaultFontData.getName(), defaultFontData.getHeight(), defaultFontData.getStyle() | SWT.BOLD); } return boldFont; } else { // default font return null; } } } class ColumnWidthSafer extends ControlAdapter { private int columnIndex; ColumnWidthSafer(int columnIndex){ this.columnIndex = columnIndex; } public void controlResized(ControlEvent e){ if (e.widget instanceof TableColumn) { TableColumn eventTableColumn = (TableColumn) e.widget; int width = eventTableColumn.getWidth(); setInitialColumnWidth(columnIndex, width); } updateDateColumnWidths(); } } /** * The constructor. */ public MesswerteView(){} private int getInitialColumnWidth(int columnIndex){ switch (columnIndex) { case PARAMETER_INDEX: return CoreHub.localCfg.get(Constants.CFG_MESSWERTE_VIEW_COLUMN_WIDTH_PREFIX + columnIndex, COLUMN_NAME_DEFAULT_WITH); case REF_INDEX: return CoreHub.localCfg.get(Constants.CFG_MESSWERTE_VIEW_COLUMN_WIDTH_PREFIX + columnIndex, COLUMN_REF_DEFAULT_WITH); default: return CoreHub.localCfg.get(Constants.CFG_MESSWERTE_VIEW_COLUMN_WIDTH_PREFIX + columnIndex, COLUMN_DATE_DEFAULT_WITH); } } private void setInitialColumnWidth(int columnIndex, int width){ CoreHub.localCfg.set(Constants.CFG_MESSWERTE_VIEW_COLUMN_WIDTH_PREFIX + columnIndex, width); } /** * This is a callback that will allow us to create the viewer and initialize it. */ public void createPartControl(Composite parent){ parent.setLayout(new GridLayout(1, false)); columnsPerPage = CoreHub.localCfg.get(Constants.CFG_MESSWERTE_VIEW_NUMBER_OF_COLUMNS, new Integer( Constants.CFG_MESSWERTE_VIEW_NUMBER_OF_COLUMNS_DEFAULT)); tableDateColumns = new TableViewerColumn[columnsPerPage]; tableDates = new TableDate[columnsPerPage]; Composite headerArea = new Composite(parent, SWT.NONE); headerArea.setLayoutData(SWTHelper.getFillGridData(1, true, 1, false)); headerArea.setLayout(new GridLayout(2, false)); Composite filterArea = new Composite(headerArea, SWT.NONE); filterArea.setLayoutData(SWTHelper.getFillGridData(1, true, 1, false)); filterArea.setLayout(new GridLayout(2, false)); Label filterLabel = new Label(filterArea, SWT.NONE); filterLabel.setText("Messwert-Gruppen:"); laborGroupsViewer = new ComboViewer(filterArea, SWT.DROP_DOWN | SWT.H_SCROLL | SWT.V_SCROLL); laborGroupsViewer.setContentProvider(new LabGroupsContentProvider()); laborGroupsViewer.setInput(this); laborGroupsViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event){ // reload the whole table reload(); } }); Composite infoArea = new Composite(headerArea, SWT.NONE); infoArea.setLayoutData(SWTHelper.getFillGridData(1, true, 1, false)); infoArea.setLayout(new GridLayout(1, false)); pagesLabel = new Label(infoArea, SWT.RIGHT); pagesLabel.setLayoutData(SWTHelper.getFillGridData(1, true, 1, false)); pagesLabel.setText(""); viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION); Table table = viewer.getTable(); table.setLayoutData(SWTHelper.getFillGridData(1, true, 1, true)); table.setHeaderVisible(true); table.setLinesVisible(true); focusCellManager = new TableViewerFocusCellManager(viewer, new FocusCellOwnerDrawHighlighter(viewer)); ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(viewer) { protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event){ return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL || event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION || (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR) || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC; } }; TableViewerEditor.create(viewer, focusCellManager, actSupport, ColumnViewerEditor.TABBING_HORIZONTAL | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION); tableNameColumn = new TableViewerColumn(viewer, SWT.LEFT); tableNameColumn.getColumn().setWidth(getInitialColumnWidth(PARAMETER_INDEX)); tableNameColumn.getColumn().addControlListener(new ColumnWidthSafer(PARAMETER_INDEX)); tableNameColumn.getColumn().setText("Parameter"); tableNameColumn.setLabelProvider(new ViewLabelProvider(PARAMETER_INDEX)); tableRefColumn = new TableViewerColumn(viewer, SWT.LEFT); tableRefColumn.getColumn().setWidth(getInitialColumnWidth(REF_INDEX)); tableRefColumn.getColumn().addControlListener(new ColumnWidthSafer(REF_INDEX)); tableRefColumn.getColumn().setText("Ref"); tableRefColumn.setLabelProvider(new ViewLabelProvider(REF_INDEX)); for (int i = 0; i < columnsPerPage; i++) { tableDateColumns[i] = new TableViewerColumn(viewer, SWT.LEFT); tableDateColumns[i].getColumn().setWidth(COLUMN_DATE_INITIAL_MIN_WIDTH); // column widths are updated by updateDateColumnWidths(); tableDates[i] = null; tableDateColumns[i].setEditingSupport(new DateEditingSupport(viewer, i)); tableDateColumns[i].setLabelProvider(new ViewLabelProvider(DATES_OFFSET + i)); } viewer.setContentProvider(new ViewContentProvider()); // viewer.setLabelProvider(new ViewLabelProvider()); viewer.setInput(getViewSite()); makeActions(); hookContextMenu(); hookDoubleClickAction(); contributeToActionBars(); initialize(); // manage date column's width (equal sizes) viewer.getTable().addControlListener(new ControlAdapter() { public void controlResized(ControlEvent e){ updateDateColumnWidths(); } }); GlobalEventDispatcher.addActivationListener(this, this); } /** * make sure the date columns have equal sizes. */ private void updateDateColumnWidths(){ int tableWidth = viewer.getTable().getSize().x; int nameColumnWidth = getInitialColumnWidth(PARAMETER_INDEX); int refColumnWidth = getInitialColumnWidth(REF_INDEX); int dateColumnsWidth = tableWidth - nameColumnWidth - refColumnWidth; if (dateColumnsWidth > 0) { int dateColumnWidth = dateColumnsWidth / columnsPerPage; int usedWidth = 0; // all date columns except last one for (int i = 0; i < tableDateColumns.length - 1; i++) { tableDateColumns[i].getColumn().setWidth(dateColumnWidth); usedWidth += dateColumnWidth; } // last column (remaining space) int remainingWidth = dateColumnsWidth - usedWidth; tableDateColumns[tableDateColumns.length - 1].getColumn().setWidth(remainingWidth); } } private void initialize(){ loadLaborGroups(); loadOwnLaborsFromConfig(); reload(); } public void dispose(){ GlobalEventDispatcher.removeActivationListener(this, this); super.dispose(); } /** * Update the labor groups in the combo */ private void loadLaborGroups(){ labGroupElements = new ArrayList<BaseLabGroupElement>(); labGroupElements.add(new AllGroupElement()); labGroupElements.add(new OwnLabsElement()); List<LabGroup> labGroups = getLabGroups(); for (LabGroup labGroup : labGroups) { Group group = new Group(labGroup); labGroupElements.add(new GroupElement(group)); } // labitem groups List<String> labItemGroups = getLabItemGroups(); for (String labItemGroup : labItemGroups) { Group group = new Group(labItemGroup); labGroupElements.add(new GroupElement(group)); } laborGroupsViewer.refresh(); selectLabGroup(labGroupElements.get(0)); } private void selectLabGroup(BaseLabGroupElement element){ IStructuredSelection sel = new StructuredSelection(element); laborGroupsViewer.setSelection(sel); } private BaseLabGroupElement getSelectedLabGroupElement(){ IStructuredSelection sel = (IStructuredSelection) laborGroupsViewer.getSelection(); BaseLabGroupElement labGroupElement = (BaseLabGroupElement) sel.getFirstElement(); return labGroupElement; } private List<LabGroup> getLabGroups(){ Query<LabGroup> query = new Query<LabGroup>(LabGroup.class); query.orderBy(false, "Name"); List<LabGroup> labGroups = query.execute(); if (labGroups == null) { labGroups = new ArrayList<LabGroup>(); } return labGroups; } private List<String> getLabItemGroups(){ List<String> labItemGroups = new ArrayList<String>(); Query<LabItem> query = new Query<LabItem>(LabItem.class); query.orderBy(false, "Gruppe"); List<LabItem> items = query.execute(); if (items != null) { for (LabItem item : items) { String groupName = item.getGroup(); if (!labItemGroups.contains(groupName)) { labItemGroups.add(groupName); } } } return labItemGroups; } private void loadOwnLaborsFromConfig(){ ownLabors = new ArrayList<Labor>(); String localLabors = CoreHub.globalCfg.get(Constants.CFG_LOCAL_LABORS, Constants.CFG_DEFAULT_LOCAL_LABORS); String[] laborIds = localLabors.split("\\s*,\\s*"); for (String laborId : laborIds) { if (!StringTool.isNothing(laborId)) { Labor labor = Labor.load(laborId); if (labor != null && labor.exists()) { ownLabors.add(labor); } } } } /** * Check if this is a "local" lab * * @param labor * the lab to test * @return true, if labor is a configured local lab */ private boolean isOwnLabor(Labor labor){ if (labor == null) { return false; } return ownLabors.contains(labor); } private void hookContextMenu(){ MenuManager menuMgr = new MenuManager("#PopupMenu"); menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager){ MesswerteView.this.fillContextMenu(manager); } }); Menu menu = menuMgr.createContextMenu(viewer.getControl()); viewer.getControl().setMenu(menu); getSite().registerContextMenu(menuMgr, viewer); } private void contributeToActionBars(){ IActionBars bars = getViewSite().getActionBars(); fillLocalPullDown(bars.getMenuManager()); fillLocalToolBar(bars.getToolBarManager()); } private void fillLocalPullDown(IMenuManager manager){ manager.add(newDateAction); manager.add(backAction); manager.add(fwdAction); // manager.add(new Separator()); } private void fillContextMenu(IMenuManager manager){ // Other plug-ins can contribute there actions here manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); // show "Pathologisch" if cell contains lab value Object element = viewer.getColumnViewerEditor().getFocusCell().getElement(); int columnIndex = viewer.getColumnViewerEditor().getFocusCell().getColumnIndex(); if (element instanceof LabRowValues) { LabRowValues labRowValues = (LabRowValues) element; if (columnIndex >= DATES_OFFSET) { int datesIndex = columnIndex - DATES_OFFSET; TableDate tableDate = tableDates[datesIndex]; if (tableDate != null) { String date = tableDate.date; int valueIndex = tableDate.index; if (!StringTool.isNothing(date)) { List<LabResult> labResults = labRowValues.results.get(date); if (labResults != null && labResults.size() > valueIndex) { LabResult labResult = labResults.get(valueIndex); boolean isPathologic = false; if (labResult.isFlag(LabResultConstants.PATHOLOGIC)) { isPathologic = true; } pathologicAction.setChecked(isPathologic); manager.add(pathologicAction); } } } } } } private void fillLocalToolBar(IToolBarManager manager){ manager.add(newDateAction); manager.add(backAction); manager.add(fwdAction); } private void makeActions(){ newDateAction = new Action() { @Override public void run(){ DateSelectorDialog dsd = new DateSelectorDialog(getViewSite().getShell()); if (dsd.open() == DateSelectorDialog.OK) { TimeTool date = dsd.getSelectedDate(); for (int i = dateColumns.size() - 1; i >= 0; i--) { DateColumn dateColumn = dateColumns.get(i); if (dateColumn.date.equals(date)) { // We already have an entry for this date MessageDialog.openInformation(PlatformUI.getWorkbench().getDisplay() .getActiveShell(), "Datumskonflikt", "Es existiert bereits ein Eintrag für dieses Datum."); return; } } boolean found = false; // update data structure (reverse for better performance, // since dates are usually added at the end for (int i = dateColumns.size() - 1; i >= 0; i--) { DateColumn dateColumn = dateColumns.get(i); TimeTool currentDate = dateColumn.date; int cmp = currentDate.compareTo(date); if (cmp < 0) { // current date is lower; insert new date after current date DateColumn newDateColumn = new DateColumn(date, 1); dateColumns.add(i + 1, newDateColumn); found = true; break; } else if (cmp == 0) { // add a new column to the current date dateColumn.numberOfColumns++; found = true; break; } } if (!found) { // new date is before any existing columns; put it at // the beginning DateColumn newDateColumn = new DateColumn(date, 1); dateColumns.add(0, newDateColumn); } prepareViewerPages(); // set current page so that the new date is visible currentPage = lastPage; // default if not found int index = -1; // find the latest corresponding column for (int i = dateColumnsExpanded.size() - 1; i >= 0; i--) { TableDate tableDate = dateColumnsExpanded.get(i); if (tableDate.date.equals(date)) { // found index = i; break; } } if (index >= 0) { // set the corresponding page int numberOfDates = dateColumnsExpanded.size(); int firstPageColumnOffset = (columnsPerPage - (numberOfDates % columnsPerPage)) % columnsPerPage; int indexInPages = index + firstPageColumnOffset; currentPage = indexInPages / columnsPerPage; } updateViewerPage(); } } }; newDateAction.setText("Neues Datum..."); newDateAction.setToolTipText("Neue Datum-Spalte erstellen"); newDateAction.setImageDescriptor(Images.IMG_ADDITEM.getImageDescriptor()); fwdAction = new Action() { @Override public void run(){ if (currentPage < lastPage) { currentPage++; updateViewerPage(); } } }; fwdAction.setText("Nächste Seite"); fwdAction.setToolTipText("Nächste Seite"); fwdAction.setImageDescriptor(Images.IMG_NEXT.getImageDescriptor()); backAction = new Action() { @Override public void run(){ if (currentPage > 0) { currentPage--; updateViewerPage(); } } }; backAction.setText("Vorherige Seite"); backAction.setToolTipText("Vorherige Seite"); backAction.setImageDescriptor(Images.IMG_PREVIOUS.getImageDescriptor()); /* * Set the currently selected lab results to "pathologic" */ pathologicAction = new Action() { @Override public void run(){ Object element = viewer.getColumnViewerEditor().getFocusCell().getElement(); int columnIndex = viewer.getColumnViewerEditor().getFocusCell().getColumnIndex(); if (element instanceof LabRowValues) { LabRowValues labRowValues = (LabRowValues) element; if (columnIndex >= DATES_OFFSET) { int datesIndex = columnIndex - DATES_OFFSET; TableDate tableDate = tableDates[datesIndex]; if (tableDate != null) { String date = tableDate.date; int valueIndex = tableDate.index; if (!StringTool.isNothing(date)) { List<LabResult> labResults = labRowValues.results.get(date); if (labResults != null && labResults.size() > valueIndex) { LabResult labResult = labResults.get(valueIndex); // isChecked() returnes the value as // activated by the user's click boolean isPathologic = isChecked(); labResult.setFlag(LabResultConstants.PATHOLOGIC, isPathologic); viewer.refresh(); } } } } } } }; pathologicAction.setText("Pathologisch"); } private void hookDoubleClickAction(){ viewer.addDoubleClickListener(new IDoubleClickListener() { public void doubleClick(DoubleClickEvent event){ doubleClicked(); } }); } private void doubleClicked(){ log.debug("doubleClicked"); ViewerCell cell = focusCellManager.getFocusCell(); Object element = cell.getElement(); if (element instanceof LabRowValues) { LabRowValues labRowValues = (LabRowValues) element; int columnIndex = cell.getColumnIndex(); if (columnIndex >= DATES_OFFSET) { int datesIndex = columnIndex - DATES_OFFSET; LabItem labItem = labRowValues.labItem; log.debug("index+" + datesIndex + ", item: " + labItem.getShortLabel()); if (labItem.getTyp() == LabItemTyp.TEXT) { StringBuffer sb = new StringBuffer(); System.getProperty("line.separator"); TableDate tableDate = tableDates[datesIndex]; if (tableDate != null) { String date = tableDate.date; int valueIndex = tableDate.index; if (!StringTool.isNothing(date)) { List<LabResult> labResults = labRowValues.results.get(date); if (labResults != null && labResults.size() > valueIndex) { LabResult labResult = labResults.get(valueIndex); sb.append(labResult.getComment()); new DisplayTextDialog(getViewSite().getShell(), "Textbefund " + date, labItem.getName(), sb.toString()).open(); } } } } } } } /** * Passing the focus request to the viewer's control. */ public void setFocus(){ viewer.getControl().setFocus(); } /** * Set new patient * * @param patient */ private void setPatient(Patient patient){ boolean changed = false; if (patient != null || actPatient != null) { // inv: not both objects are == null if (patient == null || actPatient == null) { // inv: one object == null, one object != null changed = true; } else { // inv: both objects are != null if (!patient.getId().equals(actPatient.getId())) { changed = true; } } } if (changed) { this.actPatient = patient; // reload configuration of own labors, just to be up-to-date loadOwnLaborsFromConfig(); // reload labor items and values reload(); } } /** * Re-create table and refresh values */ private void reload(){ List<LabRow> newViewerRows = new ArrayList<LabRow>(); availableDates = new ArrayList<TimeTool>(); dateColumns = new ArrayList<DateColumn>(); HashMap<String, DateColumn> dateColumnsLookup = new HashMap<String, DateColumn>(); if (actPatient != null) { BaseLabGroupElement currentLabGroupElement = getSelectedLabGroupElement(); List<LabItem> items = currentLabGroupElement.getLabItems(); if (items != null) { // specific group chosen. get available dates for this group availableDates = getAvailableDatesOfGroup(actPatient, items); } else { // all items chosen. get all dates having any lab results items = getAvailableItems(actPatient); availableDates = getAvailableDates(actPatient); } // update dateColumns from availableDates for (TimeTool time : availableDates) { // create a DateColumn with a single column per date // (will be updated while loading values below) DateColumn dateColumn = new DateColumn(time, 1); dateColumns.add(dateColumn); // dateColumnsLookup must be in human readable format dateColumnsLookup.put(time.toString(TimeTool.DATE_GER_SHORT), dateColumn); } /* * Sort LabItems use temporary comparator, as LabItem's comparator is not yet available, * as of 2008-05-29 */ Collections.sort(items, new Comparator<LabItem>() { public int compare(LabItem item1, LabItem item2){ // check for null; put null values at the end if (item1 == null) { return 1; } if (item2 == null) { return -1; } // first, compare the groups String mineGroup = item1.getGroup(); String otherGroup = item2.getGroup(); if (!mineGroup.equals(otherGroup)) { // groups differ, just compare groups return mineGroup.compareTo(otherGroup); } // compare item priorities String mine = item1.getPrio(); String others = item2.getPrio(); if ((mine.matches("[0-9]+")) && (others.matches("[0-9]+"))) { Integer iMine = Integer.parseInt(mine); Integer iOthers = Integer.parseInt(others); return iMine.compareTo(iOthers); } return mine.compareTo(others); } }); // inv: items are sorted by group/prio // if (!availableDates.isEmpty() && !items.isEmpty()) { if (!items.isEmpty()) { HashMap<String, LabRowValues> itemsLookup = new HashMap<String, LabRowValues>(); List<String> groupNames = new ArrayList<String>(); boolean isFirstGroup = true; for (LabItem item : items) { String groupName = item.getGroup(); if (groupName != null && !groupNames.contains(groupName)) { // start a new group if (isFirstGroup) { isFirstGroup = false; } else { newViewerRows.add(new LabRowSeparator()); } groupNames.add(groupName); Group group = new Group(groupName); LabRowGroup labRowGroup = new LabRowGroup(group); newViewerRows.add(labRowGroup); } // add the item (with empty values hash map) LabRowValues labRowValues = new LabRowValues(item, new HashMap<String, List<LabResult>>()); newViewerRows.add(labRowValues); // put the item/row into the lookup table using its id itemsLookup.put(item.getId(), labRowValues); } // get the results Query<LabResult> query = new Query<LabResult>(LabResult.class); query.add("PatientID", "=", actPatient.getId()); List<LabResult> labResults = query.execute(); if (labResults != null) { for (LabResult labResult : labResults) { String dateDisplay = new TimeTool(labResult.getDate()).toString(TimeTool.DATE_GER_SHORT); String dateSqlColumn = new TimeTool(labResult.getDate()).toString(TimeTool.DATE_COMPACT); LabRowValues labRowValues = itemsLookup.get(labResult.getItem().getId()); if (labRowValues != null) { List<LabResult> values = labRowValues.results.get(dateSqlColumn); if (values == null) { values = new ArrayList<LabResult>(); labRowValues.results.put(dateSqlColumn, values); } values.add(labResult); // update dateColumns (number of columns of same // date) DateColumn dateColumn = dateColumnsLookup.get(dateDisplay); if (dateColumn != null) { if (dateColumn.numberOfColumns < values.size()) { dateColumn.numberOfColumns = values.size(); } } else { log.error("Serious error for " + dateDisplay); }// else serious error! } // else, serious error! } } } } viewerRows = newViewerRows; // update data structures for all pages prepareViewerPages(); // initial page currentPage = lastPage; // set new viewport updateViewerPage(); updateDateColumnWidths(); } private void prepareViewerPages(){ dateColumnsExpanded = new ArrayList<TableDate>(); // update expand dateColumns for easier access for (DateColumn dateColumn : dateColumns) { for (int i = 0; i < dateColumn.numberOfColumns; i++) { TableDate tableDate = new TableDate(dateColumn.date, i); dateColumnsExpanded.add(tableDate); } } // update the viewer configuration int numberOfDates = dateColumnsExpanded.size(); lastPage = (numberOfDates - 1) / columnsPerPage; } private void updateViewerPage(){ // see CodeRelations.ods for calculation instructions int numberOfDates = dateColumnsExpanded.size(); int pageOffset = currentPage * columnsPerPage; int minColumnIndex = 0; for (int i = 0; i < tableDateColumns.length; i++) { if (numberOfDates > 0 && i >= minColumnIndex) { try { TableDate tableDate = null; if ((i + pageOffset) < numberOfDates) { tableDate = dateColumnsExpanded.get(i + pageOffset); // convert compact date to TimeTool.DATE_GER_SHORT for formatting String strDate = new TimeTool(tableDate.date).toString(TimeTool.DATE_GER_SHORT); tableDateColumns[i].getColumn().setText(strDate); } else { tableDateColumns[i].getColumn().setText(""); } tableDates[i] = tableDate; } catch (IndexOutOfBoundsException e) { System.out.println(e); } } else { // no date column available tableDateColumns[i].getColumn().setText(""); tableDates[i] = null; } } viewer.refresh(); if (actPatient != null) { pagesLabel.setText("Seite " + (currentPage + 1) + "/" + (lastPage + 1)); } else { pagesLabel.setText(""); } // update action status backAction.setEnabled(currentPage > 0); fwdAction.setEnabled(currentPage < lastPage); } /* * ActivationListener */ public void activation(boolean mode){ // nothing to do } public void visible(boolean mode){ if (mode == true) { ElexisEventDispatcher.getInstance().addListeners(this); Patient patient = ElexisEventDispatcher.getSelectedPatient(); setPatient(patient); } else { ElexisEventDispatcher.getInstance().removeListeners(this); setPatient(null); } } /* * HeartListener */ public void heartbeat(){ // TODO } /* ****** * 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? */ public int promptToSaveOnClose(){ return GlobalActions.fixLayoutAction.isChecked() ? ISaveablePart2.CANCEL : ISaveablePart2.NO; } public void doSave(IProgressMonitor monitor){ /* leer */ } public void doSaveAs(){ /* leer */ } public boolean isDirty(){ return true; } public boolean isSaveAsAllowed(){ return false; } public boolean isSaveOnCloseNeeded(){ return true; } /** * Class representing labor groups */ class Group { private boolean isLabGroup = false;; private LabGroup labGroup = null; private String groupName = ""; Group(LabGroup labGroup){ this.labGroup = labGroup; this.groupName = labGroup.getName(); isLabGroup = true; } Group(String groupName){ this.groupName = groupName; isLabGroup = false; } } /** * Base for LabRowGroup and LabRowValues */ interface LabRow {} // empty row as separator class LabRowSeparator implements LabRow {} /** * Class representing labor groups as rows in the viewer. */ class LabRowGroup implements LabRow { Group group; LabRowGroup(Group group){ this.group = group; } } /** * Class representing labor value rows in the viewer. The results are stored in a hash map, with * the date as the key. */ class LabRowValues implements LabRow { LabItem labItem; HashMap<String, List<LabResult>> results; LabRowValues(LabItem labItem, HashMap<String, List<LabResult>> results){ this.labItem = labItem; this.results = results; if (this.results == null) { this.results = new HashMap<String, List<LabResult>>(); } } } class DateEditingSupport extends EditingSupport { private final CellEditor valueEditor; DateEditingSupport(TableViewer viewer, int datesIndex){ super(viewer); valueEditor = new TextCellEditor(viewer.getTable()); } public CellEditor getCellEditor(Object element){ if (element instanceof LabRowValues) { log.debug("getCellEditor"); return valueEditor; } else { log.debug("no getCellEditor for " + element.getClass().getName()); return null; } } public boolean canEdit(Object element){ ViewerCell cell = focusCellManager.getFocusCell(); int columnIndex = cell.getColumnIndex(); if (element instanceof LabRowValues) { if (columnIndex >= DATES_OFFSET) { LabRowValues labRowValues = (LabRowValues) element; LabItem labItem = labRowValues.labItem; Labor labor = labItem.getLabor(); log.debug("canEdit preIsOwnLabor"); return isOwnLabor(labor); } } log.debug("canEdit false for " + element.getClass().getName()); return false; } public Object getValue(Object element){ String value = ""; ViewerCell cell = focusCellManager.getFocusCell(); int columnIndex = cell.getColumnIndex(); if (element instanceof LabRowValues) { LabRowValues labRowValues = (LabRowValues) element; if (columnIndex >= DATES_OFFSET) { int datesIndex = columnIndex - DATES_OFFSET; LabItem labItem = labRowValues.labItem; TableDate tableDate = tableDates[datesIndex]; if (tableDate != null) { String date = tableDate.date; int valueIndex = tableDate.index; if (!StringTool.isNothing(date)) { List<LabResult> results = labRowValues.results.get(date); if (results != null && results.size() > valueIndex) { LabResult labResult = results.get(valueIndex); if (labItem.getTyp() == LabItemTyp.TEXT) { value = labResult.getComment(); if (StringTool.isNothing(value)) { value = labResult.getResult(); } } else { value = labResult.getResult(); } } } } } } return value; } public void setValue(Object element, Object value){ ViewerCell cell = focusCellManager.getFocusCell(); int columnIndex = cell.getColumnIndex(); if (element instanceof LabRowValues && value instanceof String) { LabRowValues labRowValues = (LabRowValues) element; String newValue = (String) value; if (columnIndex >= DATES_OFFSET) { int datesIndex = columnIndex - DATES_OFFSET; LabItem labItem = labRowValues.labItem; TableDate tableDate = tableDates[datesIndex]; if (tableDate != null) { String date = tableDate.date; int valueIndex = tableDate.index; if (!StringTool.isNothing(date)) { List<LabResult> results = labRowValues.results.get(date); if (results == null) { results = new ArrayList<LabResult>(); labRowValues.results.put(date, results); } if (!(results.size() > valueIndex)) { // no value exists yet for this column; create // it now LabResult labResult; TimeTool timeTool = new TimeTool(date); if (labItem.getTyp() == LabItemTyp.TEXT) { labResult = new LabResult(actPatient, timeTool, labItem, "text", newValue); } else { labResult = new LabResult(actPatient, timeTool, labItem, newValue, ""); } // update data structure results.add(labResult); } else { // update LabResult labResult = results.get(valueIndex); if (labItem.getTyp() == LabItemTyp.TEXT) { labResult.set("Kommentar", newValue); } else { labResult.setResult(newValue); } } viewer.update(labRowValues, null); } } } } } } abstract class BaseLabGroupElement { abstract public String getLabel(); public String toString(){ return getLabel(); } /** * The LabItems contained in this group. return the LabItems contained in this group. A * return value of null means this group contains all available LabItems. */ abstract public List<LabItem> getLabItems(); } class AllGroupElement extends BaseLabGroupElement { public AllGroupElement(){ // nothing to do } public String getLabel(){ return GROUPS_ALL; } public List<LabItem> getLabItems(){ return null; } } class OwnLabsElement extends BaseLabGroupElement { public OwnLabsElement(){ // nothing to do } public String getLabel(){ return GROUPS_PRAXIS; } public List<LabItem> getLabItems(){ List<LabItem> ownLabsItems = new ArrayList<LabItem>(); Query<LabItem> query = new Query<LabItem>(LabItem.class); List<LabItem> labItems = query.execute(); if (labItems != null) { for (LabItem labItem : labItems) { for (Labor ownLabor : ownLabors) { if (labItem.getLabor() != null && labItem.getLabor().getId() != null && labItem.getLabor().getId().equals(ownLabor.getId())) { ownLabsItems.add(labItem); } } } } return ownLabsItems; } } class GroupElement extends BaseLabGroupElement { private Group group; public GroupElement(Group group){ this.group = group; } public String getLabel(){ return group.groupName; } public List<LabItem> getLabItems(){ List<LabItem> labItems = new ArrayList<LabItem>(); if (group.isLabGroup) { // group is of type LabGroup LabGroup labGroup = group.labGroup; labItems.addAll(labGroup.getItems()); } else { // group is just a name String groupName = group.groupName; Query<LabItem> query = new Query<LabItem>(LabItem.class); List<LabItem> groupLabItems = query.execute(); if (groupLabItems != null) { for (LabItem labItem : groupLabItems) { if (labItem.getGroup().equals(groupName)) { labItems.add(labItem); } } } } return labItems; } } class LabGroupsContentProvider implements IStructuredContentProvider { public Object[] getElements(Object parent){ return labGroupElements.toArray(); } public void dispose(){ // do nothing } public void inputChanged(Viewer v, Object oldInput, Object newInput){ // do nothing } } /** * Column instance; items of tableDates array */ class TableDate { /** * Same format as in SQL-table Laborwerte, name yyyyMMdd (DATE_COMPACT) */ String date; int index; TableDate(TimeTool date, int index){ this.date = date.toString(TimeTool.DATE_COMPACT); this.index = index; } } /** * used available dates, including number of columns of the same date */ class DateColumn { /** * Date is a Timetool object for easier and correct comparison */ TimeTool date; /** * Number of columns for the same date * * @note Manual entries are restricted to one per date */ int numberOfColumns; DateColumn(TimeTool date, int numberOfColumns){ this.date = date; this.numberOfColumns = numberOfColumns; } } public void catchElexisEvent(final ElexisEvent ev){ UiDesk.asyncExec(new Runnable() { public void run(){ if (ev.getType() == ElexisEvent.EVENT_SELECTED) { setPatient((Patient) ev.getObject()); } else if (ev.getType() == ElexisEvent.EVENT_DESELECTED) { setPatient(null); } } }); } private final ElexisEvent eetmpl = new ElexisEvent(null, Patient.class, ElexisEvent.EVENT_SELECTED | ElexisEvent.EVENT_DESELECTED); public ElexisEvent getElexisEventFilter(){ return eetmpl; } }