/*******************************************************************************
* Copyright (c) 2014 MEDEVIT <office@medevit.at>.
* 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:
* MEDEVIT <office@medevit.at> - initial API and implementation
******************************************************************************/
package ch.elexis.core.ui.contacts.views;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.JexlException;
import org.apache.commons.jexl2.MapContext;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.viewers.ILabelDecorator;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
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.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
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.Text;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import ch.elexis.core.data.beans.ContactBeanFactory;
import ch.elexis.core.data.events.ElexisEventDispatcher;
import ch.elexis.core.model.IContact;
import ch.elexis.core.ui.contacts.views.comparator.ContactSelectorViewerComparator;
import ch.elexis.core.ui.contacts.views.dnd.ContactSelectorDragListener;
import ch.elexis.core.ui.contacts.views.dnd.ContactSelectorDropListener;
import ch.elexis.core.ui.contacts.views.filter.KontaktAnzeigeTextFieldViewerFilter;
import ch.elexis.core.ui.contacts.views.filter.KontaktAnzeigeTypViewerFilter;
import ch.elexis.core.ui.contacts.views.provider.ContactSelectorObservableMapLabelProvider;
import ch.elexis.core.ui.contacts.views.provider.TableDecoratingLabelProvider;
import ch.elexis.data.Kontakt;
import ch.elexis.data.Patient;
import ch.elexis.data.Person;
import ch.elexis.data.Query;
/**
* @since 3.0.0
*/
public class ContactSelectorView extends ViewPart implements ITabbedPropertySheetPageContributor {
public static final String ID = "ch.elexis.core.ui.contacts.views.ContactSelectorView";
private ObservableListContentProvider contentProvider = null;
private TableViewer tableViewerContacts;
private WritableList contactList;
private Text txtFilter;
private KontaktAnzeigeTypViewerFilter filterAnzeigeTyp;
private KontaktAnzeigeTextFieldViewerFilter filterPositionTitle;
private LoadContactsRunnable loadContactsRunnable;
private Label lblStatus;
public ContactSelectorView(){
contactList = new WritableList();
contentProvider = new ObservableListContentProvider();
filterPositionTitle = new KontaktAnzeigeTextFieldViewerFilter();
loadContactsRunnable = new LoadContactsRunnable();
}
@Override
public void createPartControl(Composite parent){
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new GridLayout(1, false));
Composite compositeSearch = new Composite(composite, SWT.NONE);
compositeSearch.setLayout(new GridLayout(1, false));
compositeSearch.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
txtFilter = new Text(compositeSearch, SWT.BORDER | SWT.SEARCH | SWT.CANCEL);
txtFilter.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
tableViewerContacts = new TableViewer(composite, SWT.BORDER | SWT.FULL_SELECTION);
Table table = tableViewerContacts.getTable();
table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
Composite compositeStatus = new Composite(composite, SWT.NONE);
compositeStatus.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
compositeStatus.setLayout(new GridLayout(1, false));
lblStatus = new Label(compositeStatus, SWT.NONE);
lblStatus.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
tableViewerContacts.setComparator(new ContactSelectorViewerComparator(tableViewerContacts));
filterAnzeigeTyp = new KontaktAnzeigeTypViewerFilter(tableViewerContacts);
ViewerFilter[] filters = new ViewerFilter[] {
filterAnzeigeTyp, filterPositionTitle
};
tableViewerContacts.setFilters(filters);
int operations = DND.DROP_COPY | DND.DROP_MOVE;
Transfer[] transferTypes = new Transfer[] {
TextTransfer.getInstance()
};
tableViewerContacts.addDragSupport(operations, transferTypes,
new ContactSelectorDragListener(tableViewerContacts));
tableViewerContacts.addDropSupport(operations, transferTypes,
new ContactSelectorDropListener(tableViewerContacts));
txtFilter.addKeyListener(new FilterKeyListener(txtFilter, tableViewerContacts));
txtFilter.addSelectionListener(new SelectionAdapter() {
public void widgetDefaultSelected(SelectionEvent e){
if (e.detail == SWT.CANCEL) {
filterPositionTitle.setSearchText(null);
tableViewerContacts.getControl().setRedraw(false);
tableViewerContacts.refresh();
tableViewerContacts.getControl().setRedraw(true);
}
}
});
initDataBindings();
MenuManager menuManager = new MenuManager();
menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
tableViewerContacts.getTable().setMenu(
menuManager.createContextMenu(tableViewerContacts.getTable()));
getSite().registerContextMenu(menuManager, tableViewerContacts);
getSite().setSelectionProvider(tableViewerContacts);
contactList.getRealm().asyncExec(loadContactsRunnable);
tableViewerContacts
.addSelectionChangedListener(new ContactSelectionChangedToEventDispatcher());
tableViewerContacts.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event){
StructuredSelection ss = (StructuredSelection) event.getSelection();
tableViewerContacts.refresh(ss.getFirstElement());
}
});
}
protected DataBindingContext initDataBindings(){
DataBindingContext bindingContext = new DataBindingContext();
tableViewerContacts.setContentProvider(contentProvider);
IObservableMap[] observeMaps =
BeansObservables.observeMaps(contentProvider.getKnownElements(), IContact.class,
new String[] {
"description1", "description2", "mandator", "patient", "user"
});
ILabelDecorator decorator =
PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator();
tableViewerContacts.setLabelProvider(new TableDecoratingLabelProvider(
new ContactSelectorObservableMapLabelProvider(observeMaps), decorator));
tableViewerContacts.setInput(contactList);
return bindingContext;
}
public void addContact(IContact contact){
contactList.add(contact);
}
@Override
public void setFocus(){
txtFilter.setFocus();
tableViewerContacts.refresh();
}
@Override
public Object getAdapter(@SuppressWarnings("rawtypes")
Class adapter){
if (adapter == IPropertySheetPage.class)
return new TabbedPropertySheetPage(this);
return super.getAdapter(adapter);
}
@Override
public String getContributorId(){
return getSite().getId();
}
/**
* Listener for the txtFilter text control. Updates the search text filter in
* {@link KontaktAnzeigeTextFieldViewerFilter} on key press.
*/
private class FilterKeyListener extends KeyAdapter {
private Text text;
private StructuredViewer viewer;
FilterKeyListener(Text filterTxt, StructuredViewer viewer){
text = filterTxt;
this.viewer = viewer;
}
@Override
public void keyPressed(KeyEvent e){
text.setMessage("");
}
public void keyReleased(KeyEvent ke){
String txt = text.getText();
// We have a formula, if the string starts with "="
if (txt.startsWith("=")) {
String formula;
if (txt.contains(";")) {
formula = txt.substring(1, txt.indexOf(";"));
Map<String, Object> functions = new HashMap<>();
functions.put("math", Math.class);
JexlEngine jexl = new JexlEngine();
jexl.setLenient(false);
jexl.setFunctions(functions);
try {
Expression expr = jexl.createExpression(formula);
Object result = expr.evaluate(new MapContext());
text.setText("");
text.setMessage(formula + "=" + result + "");
result = null;
} catch (JexlException e) {
text.setText("");
text.setMessage("Invalid expression: " + formula);
}
}
return;
}
if (txt.length() > 1) {
filterPositionTitle.setSearchText(txt);
viewer.getControl().setRedraw(false);
viewer.refresh();
viewer.getControl().setRedraw(true);
} else {
filterPositionTitle.setSearchText(null);
viewer.getControl().setRedraw(false);
viewer.refresh();
viewer.getControl().setRedraw(true);
}
}
}
private class LoadContactsRunnable implements Runnable {
@Override
public void run(){
// Date d, e, f, g, h, i, j;
// d = new Date();
Query<Kontakt> qbe = new Query<Kontakt>(Kontakt.class, null, null, Kontakt.TABLENAME, new String[] {
Kontakt.FLD_DELETED, Kontakt.FLD_IS_PERSON, Kontakt.FLD_IS_ORGANIZATION,
Kontakt.FLD_IS_MANDATOR, Kontakt.FLD_IS_USER, Kontakt.FLD_IS_PATIENT,
Kontakt.FLD_NAME1, Kontakt.FLD_NAME2, Kontakt.FLD_NAME3, Person.BIRTHDATE,
Person.SEX, Patient.FLD_PATID, Person.TITLE, Person.FLD_TITLE_SUFFIX
});
// e = new Date();
List<Kontakt> qre = qbe.execute();
// f = new Date(); // 2598
List<? extends IContact> result = ContactBeanFactory.createContactBeans(qre);
// g = new Date();
lblStatus.setText(qbe.size() + " contacts found.");
// h = new Date(); // 4001 !!!
tableViewerContacts.getControl().setRedraw(false);
contactList.clear();
contactList.addAll(result);
// i = new Date();
// j = new Date();
tableViewerContacts.getControl().setRedraw(true);
// System.out.println("d-e: "+(e.getTime()-d.getTime()));
// System.out.println("e-f: "+(f.getTime()-e.getTime()));
// System.out.println("f-g: "+(g.getTime()-f.getTime()));
// System.out.println("g-h: "+(h.getTime()-g.getTime()));
// System.out.println("h-i: "+(i.getTime()-h.getTime()));
// System.out.println("i-j: "+(j.getTime()-i.getTime()));
// System.out.println("sum: "+(i.getTime()-d.getTime()));
}
}
/**
* Forwards selections in the contact viewer table to the ElexisEventDispatcher
*/
private class ContactSelectionChangedToEventDispatcher implements ISelectionChangedListener {
@Override
public void selectionChanged(SelectionChangedEvent event){
ISelection selection = event.getSelection();
if (selection == null)
return;
IStructuredSelection strucSelection = (IStructuredSelection) selection;
Object selectedObject = strucSelection.getFirstElement();
if (selectedObject == null)
return;
if (selectedObject instanceof IContact) {
IContact contact = (IContact) selectedObject;
if (contact.isPatient()) {
ElexisEventDispatcher.fireSelectionEvent(Patient.load(contact.getId()));
}
}
}
}
}