package com.hilotec.elexis.kgview; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Timer; import java.util.TimerTask; import org.eclipse.jface.action.Action; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.events.HyperlinkEvent; import org.eclipse.ui.forms.events.IHyperlinkListener; import org.eclipse.ui.forms.widgets.FormText; import org.eclipse.ui.forms.widgets.ScrolledFormText; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.eclipse.ui.statushandlers.StatusManager; 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.data.status.ElexisStatus; import ch.elexis.core.ui.Hub; import ch.elexis.core.ui.UiDesk; import ch.elexis.core.ui.actions.Messages; import ch.elexis.core.ui.icons.Images; import ch.elexis.core.ui.util.SWTHelper; import ch.elexis.core.ui.util.ViewMenus; import ch.elexis.data.Anwender; import ch.elexis.data.Fall; import ch.elexis.data.Konsultation; import ch.elexis.data.Patient; import ch.rgw.tools.StringTool; import ch.rgw.tools.TimeTool; import com.hilotec.elexis.kgview.data.KonsData; /** * Helper-Klasse fuers automatische scrollen mit anpassbarer Geschwindigkeit. */ class ScrollHelper implements KeyListener, DisposeListener, FocusListener { enum Direction { UP, DOWN }; private ScrolledFormText comp; private Direction dir; private Timer timer; private final int scPeriod; private final int scDistUp; private final int scDistDown; public ScrollHelper(ScrolledFormText comp){ this.comp = comp; FormText ft = comp.getFormText(); ft.addDisposeListener(this); ft.addKeyListener(this); comp.addKeyListener(this); ft.addFocusListener(this); scPeriod = Preferences.getArchivKGScrollPeriod(); scDistUp = Preferences.getArchivKGScrollDistUp(); scDistDown = Preferences.getArchivKGScrollDistDown(); } /** * Automatisches scrollen starten. Als Richtung wird 'dir' verwendet. */ private void start(){ if (timer != null) return; TimerTask tt = new TimerTask() { @Override public void run(){ UiDesk.asyncExec(new Runnable() { public void run(){ tickInGUI(); } }); } }; timer = new Timer(); timer.scheduleAtFixedRate(tt, 0, scPeriod); } /** * Automatisches scrollen stoppen. */ private void stop(){ if (timer != null) { timer.cancel(); timer = null; } } /** * Wird bei jedem Timer-Tick aufgerufen, scrollt um die festgelegte Distanz. */ public void tickInGUI(){ Point p = comp.getOrigin(); Point q = comp.getContent().getSize(); if (dir == Direction.DOWN && p.y < q.y) { p.y = Math.min(q.y, p.y + scDistDown); } else if (dir == Direction.UP && p.y > 0) { p.y = Math.max(0, p.y - scDistUp); } comp.setOrigin(p); } /* * Keyboard events */ /** * Prueft ob der Keycode fuer hoch scrollen benutzt wird. */ private boolean isUp(int kc){ return (kc == SWT.ARROW_UP || kc == SWT.PAGE_UP); } /** * Prueft ob der Keycode fuer runter scrollen benutzt wird. */ private boolean isDown(int kc){ return (kc == SWT.ARROW_DOWN || kc == SWT.PAGE_DOWN); } public void keyReleased(KeyEvent e){ if (isUp(e.keyCode) || isDown(e.keyCode)) { stop(); } } public void keyPressed(KeyEvent e){ if (isDown(e.keyCode)) { dir = Direction.DOWN; start(); } else if (isUp(e.keyCode)) { dir = Direction.UP; start(); } } /* * Events to react to */ public void widgetDisposed(DisposeEvent e){ stop(); } public void focusGained(FocusEvent e){} public void focusLost(FocusEvent e){ stop(); } } public class ArchivKG extends ViewPart implements ElexisEventListener, HeartListener { public static final String ID = "com.hilotec.elexis.kgview.ArchivKG"; ScrolledFormText text; private Action actNeueKons; private Action actNeueTelKons; private Action actNeuerHausbesuch; private Action actKonsAendern; private Action actAutoAkt; private Action actSortierungUmk; private Action actDrucken; private boolean sortRev; @Override public void createPartControl(Composite parent){ parent.setLayout(new FillLayout()); text = new ScrolledFormText(parent, true); text.getFormText().addHyperlinkListener(new IHyperlinkListener() { public void linkExited(HyperlinkEvent e){} public void linkEntered(HyperlinkEvent e){} public void linkActivated(HyperlinkEvent e){ if (!(e.getHref() instanceof String)) return; String href = (String) e.getHref(); if (href.startsWith("kons:")) { Konsultation kons = Konsultation.load(href.substring(5)); ElexisEventDispatcher.fireSelectionEvent(kons); } } }); // text.getVerticalBar().setIncrement(100); new ScrollHelper(text); sortRev = false; // TODO: Fonts fuer text laden // text.setFont("konstitel", Desk.getFont(cfgName)); createActions(); ViewMenus menus = new ViewMenus(getViewSite()); menus.createToolbar(actNeueKons, actNeueTelKons, actNeuerHausbesuch, null, actKonsAendern, actAutoAkt, actSortierungUmk, null, actDrucken); // Aktuell ausgewaehlten Patienten laden Patient pat = (Patient) ElexisEventDispatcher.getSelected(Patient.class); loadPatient(pat); ElexisEventDispatcher.getInstance().addListeners(this); } /** * @return Sortierte Liste aller Konsultation dieses Patienten */ public static ArrayList<Konsultation> getKonsultationen(Patient pat, final boolean reversed){ // Konsultationen sammeln ArrayList<Konsultation> konsliste = new ArrayList<Konsultation>(); for (Fall f : pat.getFaelle()) { for (Konsultation k : f.getBehandlungen(true)) { konsliste.add(k); } } // Konsultationen sortieren Comparator<Konsultation> comp = new Comparator<Konsultation>() { public int compare(Konsultation k0, Konsultation k1){ KonsData kd0 = KonsData.load(k0); TimeTool tt0 = new TimeTool(k0.getDatum()); tt0.setTime(new TimeTool(kd0.getKonsBeginn())); KonsData kd1 = KonsData.load(k1); TimeTool tt1 = new TimeTool(k1.getDatum()); tt1.setTime(new TimeTool(kd1.getKonsBeginn())); if (reversed) { return tt0.compareTo(tt1); } else { return tt1.compareTo(tt0); } } }; Collections.sort(konsliste, comp); return konsliste; } /** * ArchivKG zum angegebenen Patienten laden. */ private void loadPatient(Patient pat){ if (pat == null) { text.setText("Kein Patient ausgewählt!"); return; } // Inhalt fuer Textfeld generieren StringBuilder sb = new StringBuilder(); sb.append("<form>"); for (Konsultation k : getKonsultationen(pat, sortRev)) { processKonsultation(k, sb); } sb.append("</form>"); text.setText(sb.toString()); } /** * Neu laden */ private void refresh(){ loadPatient(ElexisEventDispatcher.getSelectedPatient()); } /** * sb um die die Konsultation k erweitern */ private void processKonsultation(Konsultation k, StringBuilder sb){ KonsData kd = KonsData.load(k); sb.append("<p>"); int typ = kd.getKonsTyp(); if (typ == KonsData.KONSTYP_TELEFON) { sb.append("<b>Telefon</b> "); } else if (typ == KonsData.KONSTYP_HAUSBESUCH) { sb.append("<b>Hausbesuch</b> "); } else { sb.append("<b>Konsultation</b> "); } sb.append("<a href=\"kons:" + k.getId() + "\">"); sb.append(k.getDatum() + " " + kd.getKonsBeginn() + "</a>"); // FIXME: Warum ist das noetig? if (k.getFall() != null) { sb.append(" " + k.getFall().getAbrechnungsSystem()); } String sAutor = ""; Anwender autor = kd.getAutor(); if (autor != null) { sAutor = autor.getKuerzel(); if (StringTool.isNothing(sAutor)) sAutor = autor.getLabel(); } sb.append(" (" + sAutor + ")"); sb.append("<br/>"); addParagraph("Jetziges Leiden", kd.getJetzigesLeiden(), kd.getJetzigesLeidenICPC(), sb); addParagraph("Status", kd.getLokalstatus(), sb); addParagraph("Röntgen", kd.getRoentgen(), sb); addParagraph("EKG", kd.getEKG(), sb); addParagraph("Diagnose", kd.getDiagnose(), kd.getDiagnoseICPC(), sb); addParagraph("Therapie", kd.getTherapie(), sb); addParagraph("Verlauf", kd.getVerlauf(), sb); addParagraph("Procedere", kd.getProzedere(), kd.getProzedereICPC(), sb); sb.append("</p>"); } private void addParagraph(String titel, String text, StringBuilder sb){ addParagraph(titel, text, null, sb); } private void addParagraph(String titel, String text, String icpc, StringBuilder sb){ if ((text == null || text.isEmpty()) && (icpc == null || icpc.isEmpty())) return; sb.append("<b>" + titel + "</b><br/>"); if (icpc != null && !icpc.isEmpty()) sb.append("ICPC: " + icpc.replace(",", ", ") + "<br/>"); sb.append(cleanUp(text)); sb.append("<br/><br/>"); } private String cleanUp(String text){ return text.replace(">", ">").replace("<", "<").replace("\n", "<br/>"); } public void catchElexisEvent(final ElexisEvent ev){ UiDesk.syncExec(new Runnable() { @Override public void run(){ Patient p = (Patient) ev.getObject(); if (ev.getType() == ElexisEvent.EVENT_SELECTED) { loadPatient(p); } else if (ev.getType() == ElexisEvent.EVENT_DESELECTED) { loadPatient(null); } } }); } private final ElexisEvent eetmpl = new ElexisEvent(null, Patient.class, ElexisEvent.EVENT_SELECTED | ElexisEvent.EVENT_DESELECTED); public ElexisEvent getElexisEventFilter(){ return eetmpl; } public void setFocus(){} public static class NeueKonsAct extends Action { private int typ; public NeueKonsAct(int typ){ super(Messages.GlobalActions_NewKons); setImageDescriptor(Images.IMG_NEW.getImageDescriptor()); if (typ == KonsData.KONSTYP_TELEFON) { setText("Neue Telefonkonsultation"); setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "rsc/phone.png")); setToolTipText("Neue Telefonkonsultation anlegen"); } else if (typ == KonsData.KONSTYP_HAUSBESUCH) { setText("Neuer Hausbesuch"); setImageDescriptor(Images.IMG_HOME.getImageDescriptor()); setToolTipText("Neuen Hausbesuch anlegen"); } else { setImageDescriptor(Images.IMG_NEW.getImageDescriptor()); setToolTipText(Messages.GlobalActions_NewKonsToolTip); //$NON-NLS-1$ } this.typ = typ; } @Override public void run(){ Fall fall = (Fall) ElexisEventDispatcher.getSelected(Fall.class); Patient pat = ElexisEventDispatcher.getSelectedPatient(); if (fall == null || !fall.isOpen() || !fall.getPatient().equals(pat)) { MessageDialog.openError(null, "Kein offener Fall ausgewählt", "Um eine neue Konsultation erstellen zu können, muss " + "ein offener Fall ausgewählt werden"); return; } new NeueKonsDialog(Hub.getActiveShell(), fall, typ).open(); } } public static class KonsAendernAct extends Action { KonsAendernAct(){ super("Konsultations Datum/Zeit ändern"); setImageDescriptor(Images.IMG_EDIT.getImageDescriptor()); setToolTipText("Konsultations Datum/Zeit ändern"); } @Override public void run(){ Konsultation kons = (Konsultation) ElexisEventDispatcher.getSelected(Konsultation.class); if (kons == null || !kons.isEditable(false)) { MessageDialog.openError(null, "Keine/Ungültige " + "Konsultation ausgewählt", "Es muss eine veränderbare Konsultation " + "ausgewählt sein."); return; } new NeueKonsDialog(Hub.getActiveShell(), kons).open(); } } private void createActions(){ actNeueKons = new NeueKonsAct(KonsData.KONSTYP_NORMAL); actNeueTelKons = new NeueKonsAct(KonsData.KONSTYP_TELEFON); actNeuerHausbesuch = new NeueKonsAct(KonsData.KONSTYP_HAUSBESUCH); actKonsAendern = new KonsAendernAct(); final ArchivKG akg = this; actAutoAkt = new Action("Automatisch aktualisieren", Action.AS_CHECK_BOX) { { setImageDescriptor(Images.IMG_REFRESH.getImageDescriptor()); setToolTipText("Automatisch aktualisieren"); } @Override public void run(){ boolean ch = isChecked(); if (ch) CoreHub.heart.addListener(akg); else CoreHub.heart.removeListener(akg); } }; actSortierungUmk = new Action("Sortierung umkehren", Action.AS_CHECK_BOX) { { setImageDescriptor(Images.IMG_ARROWUP.getImageDescriptor()); setToolTipText("Sortierung umkehren, älteste zuoberst"); } @Override public void run(){ sortRev = isChecked(); refresh(); } }; actDrucken = new Action("KG Drucken") { { setImageDescriptor(Images.IMG_PRINTER.getImageDescriptor()); setToolTipText("Krankengeschichte zum Drucken vorbereiten"); } @Override public void run(){ IWorkbenchPage p = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); ArchivKGPrintView apv = null; try { apv = (ArchivKGPrintView) p.showView(ArchivKGPrintView.ID); } catch (PartInitException ex) { ElexisStatus status = new ElexisStatus(ElexisStatus.WARNING, Hub.PLUGIN_ID, ElexisStatus.CODE_NONE, "Error opening part", ex, ElexisStatus.LOG_WARNINGS); StatusManager.getManager().handle(status, StatusManager.SHOW); return; } Konsultation kons = (Konsultation) ElexisEventDispatcher.getSelected(Konsultation.class); if (kons == null) { SWTHelper.showError("Keine Konsultation aktiv", "Es wird" + "eine aktive Konsultation benötigt um die KG " + "drucken und ablegen zu können."); return; } apv.doPrint(kons, null, sortRev); p.hideView(apv); } }; } @Override public void dispose(){ if (actAutoAkt.isChecked()) CoreHub.heart.removeListener(this); ElexisEventDispatcher.getInstance().removeListeners(this); super.dispose(); } @Override public void heartbeat(){ refresh(); } }