/*******************************************************************************
* Copyright (c) 2007-2015, D. Lutz 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:
* D. Lutz - initial API and implementation
* Gerry Weirich - adapted for 2.1
* Niklaus Giger - small improvements, split into 20 classes
*
* Sponsors:
* Dr. Peter Schönbucher, Luzern
******************************************************************************/
package org.iatrix.widgets;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.iatrix.Iatrix;
import org.iatrix.actions.IatrixEventHelper;
import org.iatrix.data.Problem;
import org.iatrix.util.Constants;
import org.iatrix.util.Heartbeat;
import org.iatrix.util.Heartbeat.IatrixHeartListener;
import org.iatrix.views.JournalView;
import org.iatrix.views.ProblemView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.elexis.admin.AccessControlDefaults;
import ch.elexis.core.data.activator.CoreHub;
import ch.elexis.core.data.events.ElexisEventDispatcher;
import ch.elexis.core.data.interfaces.IDiagnose;
import ch.elexis.core.ui.UiDesk;
import ch.elexis.core.ui.actions.CodeSelectorHandler;
import ch.elexis.core.ui.actions.ICodeSelectorTarget;
import ch.elexis.core.ui.dialogs.MediDetailDialog;
import ch.elexis.core.ui.util.SWTHelper;
import ch.elexis.core.ui.util.ViewMenus;
import ch.elexis.core.ui.views.codesystems.DiagnosenView;
import ch.elexis.core.ui.views.codesystems.LeistungenView;
import ch.elexis.data.Artikel;
import ch.elexis.data.Konsultation;
import ch.elexis.data.Patient;
import ch.elexis.data.PersistentObject;
import ch.elexis.data.Prescription;
import ch.elexis.icpc.Episode;
import ch.rgw.tools.ExHandler;
import ch.rgw.tools.StringTool;
import ch.rgw.tools.TimeTool;
import de.kupzog.ktable.KTableCellDoubleClickListener;
import de.kupzog.ktable.KTableCellEditor;
import de.kupzog.ktable.KTableCellSelectionListener;
import de.kupzog.ktable.SWTX;
public class ProblemArea implements IJournalArea {
private ProblemsTableModel problemsTableModel;
private MyKTable problemsKTable;
private static Logger log = LoggerFactory.getLogger(ProblemArea.class);
private ICodeSelectorTarget problemFixmedikationCodeSelectorTarget;
private ICodeSelectorTarget problemDiagnosesCodeSelectorTarget;
private String journalViewPartName;
public Action addProblemAction;
public Action delProblemAction;
public Action addFixmedikationAction;
public Action deleteFixmedikationAction;
public Action editFixmedikationAction;
private FormToolkit tk;
private Patient actPat = null;
public ProblemArea(Composite topArea, String partName, IViewSite viewSite){
tk = UiDesk.getToolkit();
journalViewPartName = partName;
problemsKTable = new MyKTable(topArea, SWTX.MARK_FOCUS_HEADERS | SWTX.AUTO_SCROLL
| SWTX.FILL_WITH_DUMMYCOL | SWTX.EDIT_ON_KEY);
tk.adapt(problemsKTable);
problemsTableModel = new ProblemsTableModel();
problemsTableModel.setProblemsKTable(problemsKTable);
problemsKTable.setModel(problemsTableModel);
makeActions(viewSite);
log.debug("addProblemAction is : " + addProblemAction);
// selections
problemsKTable.addCellSelectionListener(new KTableCellSelectionListener() {
@Override
public void cellSelected(int col, int row, int statemask){
int rowIndex = row - problemsTableModel.getFixedHeaderRowCount();
Problem problem = problemsTableModel.getProblem(rowIndex);
if (problem != null) {
IatrixEventHelper.fireSelectionEventProblem(problem);
} else {
IatrixEventHelper.clearSelectionProblem();
}
}
@Override
public void fixedCellSelected(int col, int row, int statemask){
problemsTableModel.setComparator(col, row);
reloadAndRefresh();
}
});
registerUpdateHeartbeat();
// clear selection when ESC is pressed
problemsKTable.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e){
if (e.keyCode == SWT.ESC) {
problemsKTable.clearSelection();
// work-around: KTable doesn't redraw in single selection mode
problemsKTable.redraw();
IatrixEventHelper.clearSelectionProblem();
} else if ((e.character == ' ') || (e.character == '\r')) {
// Work-around for opening the diagnosis selector on ENTER
// or changing the status.
// KTable supports only cell editors based on a Control.
// So we just catch this event ourselves and assume that KTable
// hasn't processed it in KTable.onKeyDown().
if ((e.stateMask & SWT.CTRL) == 0) {
// plain SPACE or ENTER
// This is actually the same code as in the double click listener
Point[] selection = problemsKTable.getCellSelection();
if (selection.length == 1) {
int col = selection[0].x;
int row = selection[0].y;
int colIndex = col - problemsTableModel.getFixedHeaderColumnCount();
int rowIndex = row - problemsTableModel.getFixedHeaderRowCount();
Problem problem = problemsTableModel.getProblem(rowIndex);
switch (colIndex) {
case Constants.DIAGNOSEN:
// open diagnosis selector
if (problem != null) {
try {
log.debug("doe problemDiagnosesCodeSelectorTarget");
// register as ICodeSelectorTarget
viewSite.getPage().showView(DiagnosenView.ID);
CodeSelectorHandler.getInstance().setCodeSelectorTarget(problemDiagnosesCodeSelectorTarget);
} catch (Exception ex) {
ExHandler.handle(ex);
log.error("Fehler beim Starten des Diagnosencodes "
+ ex.getMessage());
}
}
break;
case Constants.STATUS:
// change status when status field has been double clicked
if (problem != null) {
if (problem.getStatus() == Episode.ACTIVE) {
problem.setStatus(Episode.INACTIVE);
} else {
problem.setStatus(Episode.ACTIVE);
}
}
break;
}
}
} else {
// SPACE or ENTER with CTRL
Point[] selection = problemsKTable.getCellSelection();
if (selection.length == 1) {
int col = selection[0].x;
int row = selection[0].y;
int colIndex = col - problemsTableModel.getFixedHeaderColumnCount();
switch (colIndex) {
case Constants.DIAGNOSEN:
KTableCellEditor editor =
problemsTableModel.getCellEditor(col, row);
if (editor != null
&& (editor.getActivationSignals()
& KTableCellEditor.KEY_RETURN_AND_SPACE) != 0
&& editor.isApplicable(KTableCellEditor.KEY_RETURN_AND_SPACE,
problemsKTable, col, row, null, e.character + "",
e.stateMask)) {
problemsKTable.openEditorInFocus();
}
break;
}
}
}
}
}
});
problemsKTable.addCellDoubleClickListener(new KTableCellDoubleClickListener() {
@Override
public void cellDoubleClicked(int col, int row, int statemask){
int colIndex = col - problemsTableModel.getFixedHeaderColumnCount();
int rowIndex = row - problemsTableModel.getFixedHeaderRowCount();
Problem problem = problemsTableModel.getProblem(rowIndex);
switch (colIndex) {
case Constants.DIAGNOSEN:
// open diagnosis selector
if (problem != null) {
try {
// register as ICodeSelectorTarget
log.debug("problemDiagnosesCodeSelectorTarget");
viewSite.getPage().showView(DiagnosenView.ID);
CodeSelectorHandler.getInstance().setCodeSelectorTarget(problemDiagnosesCodeSelectorTarget);
} catch (Exception ex) {
ExHandler.handle(ex);
log.error("Fehler beim Starten des Diagnosencodes " + ex.getMessage());
}
}
break;
case Constants.STATUS:
// change status when status field has been double clicked
if (problem != null) {
if (problem.getStatus() == Episode.ACTIVE) {
problem.setStatus(Episode.INACTIVE);
} else {
problem.setStatus(Episode.ACTIVE);
}
log.info("Problem status changed to: " + problem.getStatus());
IatrixEventHelper.fireSelectionEventProblem(problem);
}
break;
}
}
@Override
public void fixedCellDoubleClicked(int col, int row, int statemask){
// nothing to do
}
});
// Drag'n'Drop support
// Quelle
DragSource ds = new DragSource(problemsKTable, DND.DROP_COPY);
ds.setTransfer(new Transfer[] {
TextTransfer.getInstance()
});
ds.addDragListener(new DragSourceAdapter() {
@Override
public void dragStart(DragSourceEvent event){
Point cell = problemsKTable.getCellForCoordinates(event.x, event.y);
int col = cell.x;
int row = cell.y;
// only handle normal columns/rows, no header columns/rows
if (col >= problemsTableModel.getFixedHeaderColumnCount()
&& row >= problemsTableModel.getFixedHeaderRowCount()) {
Problem problem = getSelectedProblem();
if (problem != null) {
event.doit = problem.isDragOK();
} else {
event.doit = false;
}
} else {
event.doit = false;
}
}
@Override
public void dragSetData(DragSourceEvent event){
// only add single selection
Problem problem = getSelectedProblem();
StringBuilder sb = new StringBuilder();
if (problem != null) {
sb.append(problem.storeToString()).append(",");
}
event.data = sb.toString().replace(",$", "");
}
});
// Ziel
DropTarget dt = new DropTarget(problemsKTable, DND.DROP_COPY);
dt.setTransfer(new Transfer[] {
TextTransfer.getInstance()
});
dt.addDropListener(new DropTargetListener() {
@Override
public void dragEnter(DropTargetEvent event){
// Wir machen nur Copy-Operationen
event.detail = DND.DROP_COPY;
}
// Mausbewegungen mit gedrückter Taste sind uns egal
@Override
public void dragLeave(DropTargetEvent event){}
@Override
public void dragOperationChanged(DropTargetEvent event){}
@Override
public void dragOver(DropTargetEvent event){}
// Erst das Loslassen interessiert uns wieder
@Override
public void drop(DropTargetEvent event){
String drp = (String) event.data;
String[] dl = drp.split(",");
for (String obj : dl) {
CoreHub.poFactory.createFromString(obj);
// we don't yet support dropping to the problemsKTable
}
}
@Override
public void dropAccept(DropTargetEvent event){}
});
new ICodeSelectorTarget() {
@Override
public String getName(){
return journalViewPartName;
}
@Override
public void codeSelected(PersistentObject po){
if (po instanceof IDiagnose) {
IDiagnose diagnose = (IDiagnose) po;
Problem problem = getSelectedProblem();
if (problem != null) {
problem.addDiagnose(diagnose);
IatrixEventHelper.updateProblem(problem);
if (CoreHub.userCfg.get(Iatrix.CFG_CODE_SELECTION_AUTOCLOSE,
Iatrix.CFG_CODE_SELECTION_AUTOCLOSE_DEFAULT)) {
// re-activate this view
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.showView(JournalView.ID);
} catch (Exception ex) {
ExHandler.handle(ex);
log.error("Fehler beim Öffnen von JournalView: " + ex.getMessage());
}
}
}
}
}
@Override
public void registered(boolean registered){
highlightProblemsTable(registered);
}
};
// ICodeSelectorTarget for fixmedikation in problems list
problemFixmedikationCodeSelectorTarget = new ICodeSelectorTarget() {
@Override
public String getName(){
return journalViewPartName;
}
@Override
public void codeSelected(PersistentObject po){
Problem problem = getSelectedProblem();
if (problem != null) {
if (po instanceof Artikel) {
Artikel artikel = (Artikel) po;
Prescription prescription =
new Prescription(artikel, problem.getPatient(), "", "");
problem.addPrescription(prescription);
// Let the user set the Prescription properties
MediDetailDialog dlg = new MediDetailDialog(
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
prescription);
dlg.open();
// tell other viewers that something has changed
IatrixEventHelper.updateProblem(problem);
if (CoreHub.userCfg.get(Iatrix.CFG_CODE_SELECTION_AUTOCLOSE,
Iatrix.CFG_CODE_SELECTION_AUTOCLOSE_DEFAULT)) {
// re-activate this view
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.showView(JournalView.ID);
} catch (Exception ex) {
ExHandler.handle(ex);
log.error("Fehler beim Öffnen von JournalView: " + ex.getMessage());
}
}
}
}
}
@Override
public void registered(boolean registered){
if (registered) {
highlightProblemsTable(true, true);
} else {
highlightProblemsTable(false);
}
}
};
}
private void highlightProblemsTable(boolean highlight){
highlightProblemsTable(highlight, false);
}
private void highlightProblemsTable(boolean highlight, boolean full){
problemsTableModel.setHighlightSelection(highlight, full);
problemsKTable.redraw();
}
public Problem getSelectedProblem(){
Point[] selection = problemsKTable.getCellSelection();
if (selection == null || selection.length == 0) {
return null;
} else {
int rowIndex = selection[0].y - problemsTableModel.getFixedHeaderRowCount();
Problem problem = problemsTableModel.getProblem(rowIndex);
return problem;
}
}
static class DummyProblem {}
public void reloadAndRefresh(){
problemsTableModel.reload();
problemsKTable.refresh();
}
private void makeActions(IViewSite viewSite){
delProblemAction = new Action("Problem löschen") {
@Override
public void run(){
Problem problem = getSelectedProblem();
if (problem != null) {
String label = problem.getLabel();
if (StringTool.isNothing(label)) {
label = Constants.UNKNOWN;
}
if (!CoreHub.acl.request(AccessControlDefaults.DELETE_FORCED)) {
log.error("Das Problem konnte nicht gelöscht werden: " + problem
+ " missing AccessControlDefaults.DELETE_FORCED");
SWTHelper.alert("Konnte Problem nicht löschen",
"Sie haben keine Berechtigung das Problem mit den verknüpften Daten zu löschen. (aka AccessControlDefaults.DELETE_FORCED)");
return;
}
if (MessageDialog.openConfirm(
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
"Wirklich löschen?", label) == true) {
if (problem.remove(true) == false) {
log.error("Das Problem konnte nicht gelöscht werden: " + problem);
SWTHelper.alert("Konnte Problem nicht löschen",
"Das Problem konnte nicht gelöscht werden.");
} else {
reloadAndRefresh();
}
}
}
}
};
addProblemAction = new Action("Neues Problem") {
{
setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin("org.iatrix",
"icons/new_problem.ico"));
setToolTipText("Neues Problem für diesen Patienten erstellen");
}
@Override
public void run(){
Problem problem = new Problem(ElexisEventDispatcher.getSelectedPatient(), "");
String currentDate = new TimeTool().toString(TimeTool.DATE_ISO);
problem.setStartDate(currentDate);
IatrixEventHelper.fireSelectionEventProblem(problem);
// neues Problem der aktuellen Konsulation hinzufuegen
/*
* if (actKons != null) { MessageBox mb = new MessageBox(getViewSite().getShell(),
* SWT.ICON_QUESTION | SWT.YES | SWT.NO); mb.setText("Neues Problem"); mb
* .setMessage("Neues Problem der aktuellen Konsulation zurdnen?"); if (mb.open() ==
* SWT.YES) { problem.addToKonsultation(actKons); } }
*/
reloadAndRefresh();
// select the new object
int rowIndex = problemsTableModel.getIndexOf(problem);
if (rowIndex > -1) {
int col = problemsTableModel.getFixedHeaderColumnCount();
int row = rowIndex + problemsTableModel.getFixedHeaderRowCount();
problemsKTable.setSelection(col, row, true);
}
ElexisEventDispatcher.fireSelectionEvents(actKons);
}
};
addFixmedikationAction = new Action("Fixmedikation hinzufügen") {
{
setToolTipText("Fixmedikation hinzufügen");
}
@Override
public void run(){
Point[] selection = problemsKTable.getCellSelection();
if (selection.length != 1) {
// no problem selected
SWTHelper.alert("Fixmedikation hinzufügen",
"Sie können eine Fixmedikation nur dann hinzufügen,"
+ "wenn Sie in der entsprechenden Spalte der Patientenübersicht stehen.");
return;
}
int row = selection[0].y;
int rowIndex = row - problemsTableModel.getFixedHeaderRowCount();
Problem problem = problemsTableModel.getProblem(rowIndex);
if (problem != null) {
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.showView(LeistungenView.ID);
// register as ICodeSelectorTarget
CodeSelectorHandler.getInstance()
.setCodeSelectorTarget(problemFixmedikationCodeSelectorTarget);
} catch (Exception ex) {
ExHandler.handle(ex);
log.error("Fehler beim Anzeigen der Artikel " + ex.getMessage());
}
}
}
};
editFixmedikationAction = new Action("Fixmedikation ändern...") {
{
setToolTipText("Fixmedikation ändern...");
}
@Override
public void run(){
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.showView(ProblemView.ID);
} catch (Exception ex) {
ExHandler.handle(ex);
log.error("Fehler beim Öffnen von ProblemView: " + ex.getMessage());
}
}
};
deleteFixmedikationAction = new Action("Fixmedikation entfernen...") {
{
setToolTipText("Fixmedikation entfernen...");
}
@Override
public void run(){
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.showView(ProblemView.ID);
} catch (Exception ex) {
ExHandler.handle(ex);
log.error("Fehler beim Öffnen von ProblemView: " + ex.getMessage());
}
}
};
ViewMenus menus = new ViewMenus(viewSite);
menus.createControlContextMenu(problemsKTable, addFixmedikationAction,
editFixmedikationAction, deleteFixmedikationAction);
}
public IAction getAddProblemAction(){
return addProblemAction;
}
public IAction getDelProblemAction(){
return delProblemAction;
}
public IAction getAddFixmedikationAction(){
return addFixmedikationAction;
}
public IAction getEditFixmedikationAction(){
return editFixmedikationAction;
}
public IAction getDeleteFixmedikationAction(){
return deleteFixmedikationAction;
}
private Konsultation actKons;
private boolean heartbeatProblemEnabled;
private void logEvent(String msg){
StringBuilder sb = new StringBuilder(msg + ": ");
if (actKons == null) {
sb.append("actKons null");
} else {
sb.append(actKons.getId());
sb.append(" kons vom " + actKons.getDatum());
sb.append(" " + actKons.getFall().getPatient().getPersonalia());
}
log.debug(sb.toString());
}
public void registerUpdateHeartbeat(){
Heartbeat heat = Heartbeat.getInstance();
heat.addListener(new IatrixHeartListener() {
@Override
public void heartbeat(){
logEvent("heartbeatProblem enabled " + heartbeatProblemEnabled);
if (heartbeatProblemEnabled) {
// backup selection
boolean isRowSelectMode = problemsKTable.isRowSelectMode();
Problem selectedProblem = null;
int currentColumn = -1;
if (isRowSelectMode) {
// full row selection
// not supported
} else {
// single cell selection
Point[] cells = problemsKTable.getCellSelection();
if (cells != null && cells.length > 0) {
int row = cells[0].y;
int rowIndex = row - problemsTableModel.getFixedHeaderRowCount();
selectedProblem = problemsTableModel.getProblem(rowIndex);
currentColumn = cells[0].x;
}
}
// reload data
reloadAndRefresh();
// restore selection
if (selectedProblem != null) {
if (isRowSelectMode) {
// full row selection
// not supported
} else {
// single cell selection
int rowIndex = problemsTableModel.getIndexOf(selectedProblem);
if (rowIndex >= 0) {
// problem found, i. e. still in list
int row = rowIndex + problemsTableModel.getFixedHeaderRowCount();
if (currentColumn == -1) {
currentColumn = problemsTableModel.getFixedHeaderColumnCount();
}
problemsKTable.setSelection(currentColumn, row, true);
}
}
}
}
}
});
}
/*
* Aktuelle Konsultation und Patienten setzen
*/
@Override
public void setKons(Konsultation newKons, KonsActions op){
if (newKons == null )
{
actKons = newKons;
actPat = null;
} else {
Patient newPatient = newKons.getFall().getPatient();
if (newPatient == null) { return; } // this should never happen as kons always has a patient
log.debug("setPatient " + newPatient.getPersonalia());
if (actPat == null || !actPat.getId().equals(newPatient.getId())) {
actPat = newPatient;
actKons = newKons;
problemsTableModel.setPatient(newPatient);
reloadAndRefresh();
}
}
}
public MyKTable getProblemKTable(){
return problemsKTable;
}
public ProblemsTableModel getProblemsTableModel(){
return problemsTableModel;
}
@Override
public void visible(boolean mode){}
@Override
public void activation(boolean mode){
if (mode == true) {
log.debug("activation " + mode);
setKons((Konsultation) ElexisEventDispatcher.getSelected(Konsultation.class),KonsActions.ACTIVATE_KONS);
} else {
setKons(null, KonsActions.ACTIVATE_KONS);
}
}
}