/******************************************************************************* * Copyright (c) 2006-2009, Daniel 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: * Daniel Lutz - initial implementation * Gerry Weirich - adapted to use the new AccountTransaction-class * actions added * *******************************************************************************/ package ch.elexis.core.ui.views.rechnung; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.math.NumberUtils; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.Action; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.ui.ISaveablePart2; import org.eclipse.ui.forms.widgets.Form; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.part.ViewPart; import ch.elexis.core.data.events.ElexisEvent; import ch.elexis.core.data.events.ElexisEventDispatcher; import ch.elexis.core.data.events.ElexisEventListenerImpl; import ch.elexis.core.ui.UiDesk; import ch.elexis.core.ui.actions.BackgroundJob; import ch.elexis.core.ui.actions.BackgroundJob.BackgroundJobListener; 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.AddBuchungDialog; import ch.elexis.core.ui.events.ElexisUiEventListenerImpl; 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.AccountTransaction; import ch.elexis.data.AccountTransaction.Account; import ch.elexis.data.Patient; import ch.elexis.data.Query; import ch.elexis.data.Rechnung; import ch.rgw.tools.Money; /** * This view shows the current patient's account */ public class AccountView extends ViewPart implements IActivationListener, ISaveablePart2 { public static final String ID = "ch.elexis.views.rechnung.AccountView"; //$NON-NLS-1$ private static final String ACCOUNT_EXCESS_JOB_NAME = Messages.AccountView_calculateBalance; //$NON-NLS-1$ private BackgroundJob accountExcessJob; private FormToolkit tk; private Form form; private Label balanceLabel; private Label excessLabel; private TableViewer accountViewer; private Patient actPatient; private Action addPaymentAction, removePaymentAction; private int sortColumn; private boolean sortReverse; // column indices private static final int DATE = 0; private static final int AMOUNT = 1; private static final int BILL = 2; private static final int REMARKS = 3; private static final int ACCOUNT = 4; private static final String[] COLUMN_TEXT = { Messages.AccountView_date, // DATE Messages.AccountView_amount, // AMOUNT Messages.AccountView_bill, // BILL Messages.AccountView_remarks, // REMARKS Messages.AccountView_account, // ACCOUNT }; private static final int[] COLUMN_WIDTH = { 80, // DATE 80, // AMOUNT 80, // BILL 160, // REMARKS 80 // ACCOUNT }; private ElexisEventListenerImpl eeli_pat = new ElexisUiEventListenerImpl(Patient.class) { public void runInUi(ElexisEvent ev){ if (ev.getType() == ElexisEvent.EVENT_SELECTED) { Patient selectedPatient = (Patient) ev.getObject(); setPatient(selectedPatient); } else if (ev.getType() == ElexisEvent.EVENT_DESELECTED) { setPatient(null); } } }; private ElexisEventListenerImpl eeli_at = new ElexisUiEventListenerImpl(AccountTransaction.class) { public void runInUi(ElexisEvent ev){ removePaymentAction.setEnabled(ev.getType() == ElexisEvent.EVENT_SELECTED); } }; public void createPartControl(Composite parent){ initializeJobs(); parent.setLayout(new FillLayout()); tk = UiDesk.getToolkit(); form = tk.createForm(parent); form.getBody().setLayout(new GridLayout(1, false)); // account infos Composite accountArea = tk.createComposite(form.getBody()); accountArea.setLayoutData(SWTHelper.getFillGridData(1, true, 1, false)); accountArea.setLayout(new GridLayout(3, false)); tk.createLabel(accountArea, Messages.AccountView_account); //$NON-NLS-1$ tk.createLabel(accountArea, Messages.AccountView_accountAmount); //$NON-NLS-1$ balanceLabel = tk.createLabel(accountArea, ""); //$NON-NLS-1$ balanceLabel.setLayoutData(SWTHelper.getFillGridData(1, true, 1, false)); tk.createLabel(accountArea, ""); // dummy //$NON-NLS-1$ tk.createLabel(accountArea, Messages.AccountView_goodFromBills); //$NON-NLS-1$ excessLabel = tk.createLabel(accountArea, ""); //$NON-NLS-1$ excessLabel.setLayoutData(SWTHelper.getFillGridData(1, true, 1, false)); // account entries accountViewer = new TableViewer(form.getBody(), SWT.SINGLE | SWT.FULL_SELECTION); Table table = accountViewer.getTable(); table.setLayoutData(SWTHelper.getFillGridData(1, true, 1, true)); tk.adapt(table); table.setHeaderVisible(true); table.setLinesVisible(true); SelectionAdapter sortListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e){ TableColumn col = (TableColumn) e.getSource(); Integer colNo = (Integer) col.getData(); if (colNo == sortColumn) { sortReverse = !sortReverse; } else { sortReverse = false; sortColumn = colNo; } accountViewer.getTable().setSortDirection(sortReverse ? SWT.DOWN : SWT.UP); accountViewer.getTable().setSortColumn(col); accountViewer.refresh(); } }; // columns TableColumn[] tc = new TableColumn[COLUMN_TEXT.length]; for (int i = 0; i < COLUMN_TEXT.length; i++) { tc[i] = new TableColumn(table, SWT.NONE); tc[i].setText(COLUMN_TEXT[i]); tc[i].setWidth(COLUMN_WIDTH[i]); tc[i].setData(new Integer(i)); tc[i].addSelectionListener(sortListener); } accountViewer.setContentProvider(new IStructuredContentProvider() { public Object[] getElements(Object inputElement){ if (actPatient == null) { return new Object[] { Messages.AccountView_NoPatientSelected }; } Query<AccountTransaction> qa = new Query<AccountTransaction>(AccountTransaction.class); qa.add(AccountTransaction.FLD_PATIENT_ID, Query.EQUALS, actPatient.getId()); qa.orderBy(true, new String[] { AccountTransaction.FLD_DATE }); return qa.execute().toArray(); } public void dispose(){ // nothing to do } public void inputChanged(Viewer viewer, Object oldInput, Object newInput){ // nothing to do } }); accountViewer.setLabelProvider(new ITableLabelProvider() { public void addListener(ILabelProviderListener listener){ // nothing to do } public void removeListener(ILabelProviderListener listener){ // nothing to do } public void dispose(){ // nothing to do } public String getColumnText(Object element, int columnIndex){ if (!(element instanceof AccountTransaction)) { return ""; } AccountTransaction entry = (AccountTransaction) element; String text = ""; Account account = null; switch (columnIndex) { case DATE: text = entry.get("Datum"); break; case AMOUNT: text = entry.getAmount().getAmountAsString(); break; case BILL: Rechnung rechnung = entry.getRechnung(); if (rechnung != null && rechnung.exists()) { text = rechnung.getNr(); } else { text = ""; //$NON-NLS-1$ } break; case REMARKS: text = entry.getRemark(); break; case ACCOUNT: account = entry.getAccount(); if (account != null && account != Account.UNKNOWN) { text = account.getName(); } break; } return text; } public Image getColumnImage(Object element, int columnIndex){ return null; } public boolean isLabelProperty(Object element, String property){ return false; } }); accountViewer.setSorter(new AccountTransactionSorter()); // viewer.setSorter(new NameSorter()); accountViewer.setInput(getViewSite()); /* * makeActions(); hookContextMenu(); hookDoubleClickAction(); contributeToActionBars(); */ makeActions(); ViewMenus menu = new ViewMenus(getViewSite()); menu.createToolbar(addPaymentAction /* * do not use yet ,removePaymentAction */); removePaymentAction.setEnabled(false); GlobalEventDispatcher.addActivationListener(this, this); accountViewer.addSelectionChangedListener(GlobalEventDispatcher.getInstance() .getDefaultListener()); if (sortColumn == DATE) { sortReverse = true; } } private void initializeJobs(){ accountExcessJob = new AccountExcessJob(ACCOUNT_EXCESS_JOB_NAME); accountExcessJob.addListener(new BackgroundJobListener() { public void jobFinished(BackgroundJob j){ setKontoText(); } }); accountExcessJob.schedule(); } private void finishJobs(){ accountExcessJob.cancel(); } /** * Passing the focus request to the viewer's control. */ public void setFocus(){ accountViewer.getControl().setFocus(); } @Override public void dispose(){ finishJobs(); GlobalEventDispatcher.removeActivationListener(this, this); accountViewer.removeSelectionChangedListener(GlobalEventDispatcher.getInstance() .getDefaultListener()); super.dispose(); } private void setPatient(Patient patient){ actPatient = patient; // start calculating account excess accountExcessJob.invalidate(); accountExcessJob.schedule(); String title = ""; //$NON-NLS-1$ if (actPatient != null) { title = actPatient.getLabel(); } else { title = Messages.AccountView_NoPatientSelected; //$NON-NLS-1$ } form.setText(title); setKontoText(); accountViewer.refresh(); form.layout(); } // maybe called from foreign thread private void setKontoText(){ // check wheter the labels are valid, since we may be called // from a different thread if (balanceLabel.isDisposed() || excessLabel.isDisposed()) { return; } String balanceText = ""; //$NON-NLS-1$ String excessText = "..."; //$NON-NLS-1$ if (actPatient != null) { balanceText = actPatient.getKontostand().getAmountAsString(); if (accountExcessJob.isValid()) { Object jobData = accountExcessJob.getData(); if (jobData instanceof Money) { Money accountExcess = (Money) jobData; excessText = accountExcess.getAmountAsString(); } } } balanceLabel.setText(balanceText); excessLabel.setText(excessText); } /* * SelectionListener methods */ /* * ActivationListener */ public void activation(boolean mode){ // nothing to do } public void visible(boolean mode){ if (mode == true) { ElexisEventDispatcher.getInstance().addListeners(eeli_at, eeli_pat); Patient patient = ElexisEventDispatcher.getSelectedPatient(); setPatient(patient); } else { ElexisEventDispatcher.getInstance().removeListeners(eeli_at, eeli_pat); setPatient(null); } }; /* * 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 AccountEntry { TimeTool date; Money amount; String remarks; * * AccountEntry(TimeTool date, Money amount, String remarks) { this.date = date; this.amount = * amount; this.remarks = remarks; * * if (remarks == null) { remarks = ""; } } } */ private void makeActions(){ addPaymentAction = new Action(Messages.AccountView_addBookingCaption) { //$NON-NLS-1$ { setToolTipText(Messages.AccountView_addBookingBody); //$NON-NLS-1$ setImageDescriptor(Images.IMG_ADDITEM.getImageDescriptor()); } @Override public void run(){ if (new AddBuchungDialog(getViewSite().getShell(), actPatient).open() == Dialog.OK) { setPatient(actPatient); } } }; removePaymentAction = new Action(Messages.AccountView_deleteBookingAction) { //$NON-NLS-1$ { setToolTipText(Messages.AccountView_deleteBookingTooltip); //$NON-NLS-1$ setImageDescriptor(Images.IMG_DELETE.getImageDescriptor()); } @Override public void run(){ AccountTransaction at = (AccountTransaction) ElexisEventDispatcher .getSelected(AccountTransaction.class); if (at != null) { if (SWTHelper.askYesNo(Messages.AccountView_deleteBookingConfirmCaption, //$NON-NLS-1$ Messages.AccountView_deleteBookingConfirmBody)) { //$NON-NLS-1$ at.delete(); setPatient(actPatient); } } } }; } class AccountExcessJob extends BackgroundJob { public AccountExcessJob(String name){ super(name); } public IStatus execute(IProgressMonitor monitor){ if (AccountView.this.actPatient != null) { result = actPatient.getAccountExcess(); } else { result = null; } // return new Status(IStatus.OK, Hub.PLUGIN_ID, IStatus.OK, // "Daten geladen", null); return Status.OK_STATUS; } public int getSize(){ return 1; } } class AccountTransactionSorter extends ViewerSorter { @Override public int compare(Viewer viewer, Object e1, Object e2){ if ((e1 instanceof AccountTransaction) && (e2 instanceof AccountTransaction)) { AccountTransaction accountTransaction1 = (AccountTransaction) e1; AccountTransaction accountTransaction2 = (AccountTransaction) e2; int retVal = 0; switch (sortColumn) { case DATE: retVal = ObjectUtils.compare(accountTransaction1.getDate(), accountTransaction2.getDate()); break; case AMOUNT: retVal = ObjectUtils.compare(accountTransaction1.getAmount(), accountTransaction2.getAmount()); break; case BILL: Rechnung rechnung1 = accountTransaction1.getRechnung(); Rechnung rechnung2 = accountTransaction2.getRechnung(); if (rechnung1 == null) retVal = -1; else if (rechnung2 == null) retVal = 1; else retVal = ObjectUtils.compare(NumberUtils.toInt(rechnung1.getNr()), NumberUtils.toInt(rechnung2.getNr())); break; case REMARKS: retVal = ObjectUtils.compare(accountTransaction1.getRemark(), accountTransaction2.getRemark()); break; case ACCOUNT: retVal = ObjectUtils.compare(accountTransaction1.getAccount().getName(), accountTransaction2.getAccount().getName()); break; } return sortReverse ? retVal * -1 : retVal; } return 0; } } }