/******************************************************************************* * Copyright (c) 2006-2009, G. Weirich 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: * G. Weirich - initial implementation * *******************************************************************************/ package ch.elexis.core.ui.util.viewers; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.forms.events.HyperlinkAdapter; import org.eclipse.ui.forms.events.HyperlinkEvent; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Hyperlink; import org.eclipse.ui.forms.widgets.ImageHyperlink; import ch.elexis.core.ui.UiDesk; import ch.elexis.core.ui.icons.Images; import ch.elexis.core.ui.text.ElexisText; import ch.elexis.core.ui.util.Messages; import ch.elexis.core.ui.util.SWTHelper; import ch.elexis.core.ui.util.viewers.ViewerConfigurer.ControlFieldListener; import ch.elexis.core.ui.util.viewers.ViewerConfigurer.ControlFieldProvider; import ch.elexis.data.PersistentObject; import ch.elexis.data.Query; import ch.rgw.tools.IFilter; import ch.rgw.tools.StringTool; import ch.rgw.tools.Tree; /** * Standardimplementation des ControlFieldProviders. Erzeugt ein Composite mit je einem * Texteingabefeld für jedes beim Konstruktor übergebene Feld. Feuert einen ChangedEvent, wenn * mindestens zwei Zeichen in eins der Felder eingegeben wurden. * * @author Gerry */ public class DefaultControlFieldProvider implements ControlFieldProvider { protected String[] dbFields, fields, lastFiltered; protected ElexisText[] selectors; protected final ModListener ml; protected final SelListener sl; protected boolean modified; protected final List<ControlFieldListener> listeners; private final FormToolkit tk; protected CommonViewer myViewer; protected int focusField; boolean bCeaseFire; private Composite inner; public DefaultControlFieldProvider(final CommonViewer viewer, final String[] flds){ myViewer = viewer; updateFields(flds, false); ml = new ModListener(); sl = new SelListener(); listeners = new LinkedList<ControlFieldListener>(); tk = UiDesk.getToolkit(); } /** * Update and optionally redraw the control fields to order the content. * * @param flds * @param redraw * redraw the fields * @since 3.1.0 */ public void updateFields(String[] flds, boolean redraw){ fields = new String[flds.length]; dbFields = new String[fields.length]; focusField = 0; // this.fields=new String[fields.length]; lastFiltered = new String[fields.length]; for (int i = 0; i < flds.length; i++) { lastFiltered[i] = ""; //$NON-NLS-1$ if (flds[i].indexOf('=') != -1) { String[] s = flds[i].split("="); //$NON-NLS-1$ fields[i] = s[1]; dbFields[i] = s[0]; } else { fields[i] = dbFields[i] = flds[i]; } } if (redraw) { inner.setRedraw(false); Control[] children = inner.getChildren(); for (Control control : children) { control.dispose(); } GridLayout lRet = new GridLayout(fields.length, true); inner.setLayout(lRet); populateInnerComposite(); inner.setRedraw(true); } } private void populateInnerComposite(){ for (String l : fields) { Hyperlink hl = tk.createHyperlink(inner, l, SWT.NONE); hl.addHyperlinkListener(new HyperlinkAdapter() { @Override public void linkActivated(final HyperlinkEvent e){ Hyperlink h = (Hyperlink) e.getSource(); fireSortEvent(h.getText()); } }); hl.setBackground(inner.getBackground()); } createSelectors(fields.length); for (int i = 0; i < selectors.length; i++) { selectors[i] = new ElexisText(tk.createText(inner, "", SWT.BORDER)); //$NON-NLS-1$ selectors[i].addModifyListener(ml); selectors[i].addSelectionListener(sl); selectors[i].setToolTipText(Messages.DefaultControlFieldProvider_enterFilter); //$NON-NLS-1$ selectors[i].setLayoutData(SWTHelper.getFillGridData(1, true, 1, false)); SWTHelper.setSelectOnFocus((Text) selectors[i].getWidget()); } } @Override public Composite createControl(final Composite parent){ // Form form=tk.createForm(parent); // form.setLayoutData(SWTHelper.getFillGridData(1,true,1,false)); // Composite ret=form.getBody(); Composite ret = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(2, false); layout.marginWidth = 0; ret.setLayout(layout); ret.setBackground(parent.getBackground()); ImageHyperlink hClr = tk.createImageHyperlink(ret, SWT.NONE); //$NON-NLS-1$ hClr.setImage(Images.IMG_CLEAR.getImage()); hClr.addHyperlinkListener(new HyperlinkAdapter() { @Override public void linkActivated(final HyperlinkEvent e){ clearValues(); } }); hClr.setBackground(parent.getBackground()); inner = new Composite(ret, SWT.NONE); GridLayout lRet = new GridLayout(fields.length, true); inner.setLayout(lRet); inner.setLayoutData(SWTHelper.getFillGridData(1, true, 1, true)); populateInnerComposite(); return ret; } protected void createSelectors(int length){ selectors = new ElexisText[fields.length]; } /** * Setze Feld welches den Fokus erhaelt * * @param index * Index im field array */ public void setFocusField(int index){ if (index >= fields.length) throw new IndexOutOfBoundsException("Invalid field index"); focusField = index; } /** * Setze Feld welches den Fokus erhaelt (nach DB name). Ein ungueltiger Name wird ignoriert. * * @param name * DB-Namen des Feldes */ public void setFocusField(String name){ for (int i = 0; i < dbFields.length; i++) { if (dbFields[i].equals(name)) focusField = i; } } @Override public void setFocus(){ selectors[focusField].setFocus(); } public boolean isModified(){ return modified; } public String[] getDBFields(){ return dbFields; } /** * Reaktion auf Eingaben in die Filterfelder. Reagiert erst wenn mindestens zwei Zeichen * eingegeben wurden oder das Feld geleert wurde. * */ class ModListener implements ModifyListener { @Override public void modifyText(final ModifyEvent e){ modified = true; Text t = (Text) e.getSource(); String s = t.getText(); if (!StringTool.leer.equals(s)) { if (s.length() == 1) { return; } } for (int i = 0; i < lastFiltered.length; i++) { lastFiltered[i] = selectors[i].getText(); } fireChangedEvent(); } } /** * Reaktion auf ENTER den Filterfelder. Weist den Viewer an, eine Selektion vorzunehmen. */ class SelListener implements SelectionListener { @Override public void widgetSelected(final SelectionEvent e){ fireSelectedEvent(); } @Override public void widgetDefaultSelected(final SelectionEvent e){ widgetSelected(e); } } @Override public void fireChangedEvent(){ if (!bCeaseFire) { UiDesk.getDisplay().syncExec(new Runnable() { @Override public void run(){ HashMap<String, String> hm = new HashMap<String, String>(); for (int i = 0; i < fields.length; i++) { hm.put(fields[i], lastFiltered[i]); } for (ControlFieldListener lis : listeners) { lis.changed(hm); } } }); } } @Override public void fireSortEvent(final String text){ if (!bCeaseFire) { for (ControlFieldListener ls : listeners) { ls.reorder(text); } } } public void fireSelectedEvent(){ if (!bCeaseFire) { for (ControlFieldListener ls : listeners) { ls.selected(); } } } @Override public void addChangeListener(final ControlFieldListener cl){ listeners.add(cl); } @Override public void removeChangeListener(final ControlFieldListener cl){ listeners.remove(cl); } @Override public String[] getValues(){ return lastFiltered; } public Composite getParent(){ return inner; } /** * Alle Eingabefelder löschen und einen "changeEvent" feuern". Aber nur, wenn die Felder nicht * schon vorher leer waren. */ @Override public void clearValues(){ myViewer.getViewerWidget().setSelection(null); if (!isEmpty()) { bCeaseFire = true; for (int i = 0; i < selectors.length; i++) { selectors[i].setText(StringTool.leer); lastFiltered[i] = StringTool.leer; } modified = false; bCeaseFire = false; fireChangedEvent(); } } /** * Set a value on the filters specific index. Does not call {@link #fireChangedEvent()}. * * @param index * @param value * @since 3.2 */ public void setValue(int index, String value){ if (index > lastFiltered.length) { return; } bCeaseFire = true; selectors[index].setText(value); lastFiltered[index] = value; modified = true; bCeaseFire = false; } @Override public void setQuery(final Query q){ boolean ch = false; for (int i = 0; i < fields.length; i++) { if (!lastFiltered[i].equals(StringTool.leer)) { q.add(dbFields[i], "LIKE", lastFiltered[i] + "%", true); //$NON-NLS-1$ //$NON-NLS-2$ q.and(); ch = true; } } if (ch) { q.insertTrue(); } } @Override public IFilter createFilter(){ return new DefaultFilter(); } private class DefaultFilter extends ViewerFilter implements IFilter { @Override public boolean select(Viewer viewer, Object parentElement, Object element){ return select(element); } @Override public boolean select(Object element){ PersistentObject po = null; if (element instanceof Tree) { po = (PersistentObject) ((Tree) element).contents; } else if (element instanceof PersistentObject) { po = (PersistentObject) element; } else { return false; } if (po.isMatching(dbFields, PersistentObject.MATCH_START, lastFiltered)) { return true; } else { if (element instanceof Tree) { Tree p = ((Tree) element).getParent(); if (p == null) { return false; } return select(p); } else { return false; } } } } @Override public boolean isEmpty(){ for (String s : lastFiltered) { if (!s.equals(StringTool.leer)) { return false; } } return true; } public void ceaseFire(final boolean bCeaseFire){ this.bCeaseFire = bCeaseFire; } public CommonViewer getCommonViewer(){ return this.myViewer; } }