All Downloads are FREE. Search and download functionalities are using the official Maven repository.

at.spardat.xma.mdl.table.TableUIDelegateClient Maven / Gradle / Ivy

There is a newer version: 6.0.2
Show newest version
/*******************************************************************************
 * Copyright (c) 2003, 2007 s IT Solutions AT Spardat GmbH .
 * 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:
 *     s IT Solutions AT Spardat GmbH - initial API and implementation
 *******************************************************************************/

// @(#) $Id: TableUIDelegateClient.java 9343 2012-04-18 15:02:39Z mjohannes $
package at.spardat.xma.mdl.table;

import java.text.Collator;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Locale;
import java.util.ResourceBundle;

import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Widget;

import at.spardat.enterprise.fmt.IFmt;
import at.spardat.enterprise.util.Types;
import at.spardat.xma.component.ComponentClient;
import at.spardat.xma.mdl.Atom;
import at.spardat.xma.mdl.AttachmentExceptionClient;
import at.spardat.xma.mdl.ModelChangeEvent;
import at.spardat.xma.mdl.UIDelegateClient;
import at.spardat.xma.mdl.WModel;
import at.spardat.xma.mdl.table.XMATableColumn.AtomComparator;
import at.spardat.xma.mdl.util.TransAtomTable;
import at.spardat.xma.page.EventAdapter;
import at.spardat.xma.page.PageClient;
import at.spardat.xma.page.Scaler;
import at.spardat.xma.util.Assert;

/**
 * This class manages the UI related aspects of a TableWMClient widget model
 *
 * @author YSD, 27.04.2003 16:29:53
 */
public class TableUIDelegateClient extends UIDelegateClient {
    /** resource bundle containing all localized strings of PagingControlClient */
    private static final String resourceBundle = "at.spardat.xma.mdl.table.Table";
    
    //Pathes to the sort-arrow-icons - used if setSortIndicator(true)
    private static final String ARROW_UP_ICON = "at/spardat/xma/mdl/table/icons/sortarrow_up.gif";
    private static final String ARROW_DOWN_ICON = "at/spardat/xma/mdl/table/icons/sortarrow_down.gif";
    private static final String ARROW_EMPTY_ICON = "at/spardat/xma/mdl/table/icons/sortarrow_empty.gif";

    /**
     * The widget model this UI delegate belongs to
     */
    private TableWMClient                   wModel_;

    /**
     * drawn from the table model and redundantly stored here
     */
    private int                             columnCount_;

    /**
     * The SWT table
     */
    private Table                           table_;
    

    /**
     * Keep track of whether we are updating the UI.
     */
    private boolean                         updatingUI_ = false;

    /**
     * The model index of the column used to sort the table. Is -1 if
     * the table is shown in natural order.
     */
    private int                             sortingCol_ = -1;

    /**
     * If sortingCol_ != -1, indicates if the column is sorted ascending
     */
    private boolean                         ascending = true;

    /**
     * Holds as many Integer-objects as there are rows in the widget
     * model. The entry e(i) at index i specifies that the row
     * at index i in the SWT table maps to the row at
     * index e(i) in the widget model.
     */
    private ArrayList                       sortPermutation_;

    /**
     * Maps SWT column indexes to model indexes. The SWT column
     * at index i belongs to the model column at
     * index swtCol2ModelCol_[i].
     */
    private int []                          swtCol2ModelCol_;

    /**
     * Maps model column indexes to SWT column indexes. The
     * model column at index i is mapped to the SWT
     * table column at index modelCol2SwtCol_[i].
     */
    private int []                          modelCol2SwtCol_;

    /**
     * Editable-state
     */
    private boolean                         editable_ = true;

    /**
     * Enable-state
     */
    protected boolean                         enabled_ = true;


    /**
     * If showSortIndicator_ is true then a sort indicator is shown at the sorting column's header.
     */
    private boolean                         showSortIndicator_ = false;

    /**
     * external sorter to use instead of the internal implementation if not null
     */
    private TableExternalSorterClient       externalSorter_;
    
    /** 
     * Menu Item that allows for copying value to clipboard
     */
    private MenuItem                        copyMenuItem_;
    
    /** 
     * Menu Item that allows for copying value to clipboard
     */
    private String                          copyMenuClipboardText_;
    
    /**
     * Constructor
     *
     * @param wModel the widget model this UI delegate belongs to
     */
    public TableUIDelegateClient (TableWMClient wModel) {
        wModel_ = wModel;
        columnCount_ = wModel.columnCount_;
    }

    /**
     * The attached Table must delegate its SelectionEvent to this method in order
     * to keep track of the selection state of the table. Moreover, if the table
     * is sortable, the SelectionEvents of every TableColumn must also be
     * notified.
     *
     * @see at.spardat.xma.mdl.UIDelegateClient#handleUIEvent(java.lang.Object, int)
     */
    public void handleUIEvent (Object event, int type) {
        if (!isUIAttached()) return;
        if (updatingUI_) {
            return;
        }
        if (Assert.ON) debugInvariant();
        realInvariant();

        updatingUI_ = true;
        try {
            handleUIEventInternal(event);
        } finally {
            updatingUI_ = false;
        }
        if (Assert.ON) debugInvariant();
        realInvariant();
    }

    protected void handleUIEventInternal (Object event) {
        if (event instanceof SelectionEvent) {
            SelectionEvent selectionEvent = (SelectionEvent) event;
            // selection event on the table
            if (selectionEvent.widget == table_) {
                handleTableSelect();
            } else if (selectionEvent.widget instanceof TableColumn) {
                handleColumnSelect(selectionEvent);
            } else if (selectionEvent.widget == copyMenuItem_) {
                handleCopy();
            }
        } else if (event instanceof MouseEvent) {
            MouseEvent mouseEvent = (MouseEvent)event;
            if (mouseEvent.widget == table_ && mouseEvent.button == 3){
                // Rightclick in table: Find out value for copy of text in table cell
                TableItem[] selection = table_.getSelection();
                int column = getColumnAt(table_, mouseEvent);
                copyMenuClipboardText_ = selection.length>0 ? selection[0].getText(column) : "";
                ResourceBundle messages = ResourceBundle.getBundle(resourceBundle,getLocale());
                String menuText = MessageFormat.format(messages.getString("copyCellText"), new Object[] { copyMenuClipboardText_} );
                if (copyMenuItem_!= null)
                    copyMenuItem_.setText(menuText);
            }
        }
    }

    protected void handleCopy() {
        // Context menu selected: copy cell value to clipboard
        if (copyMenuClipboardText_ != null && copyMenuClipboardText_.length()>0) {
            Display display = table_.getShell().getDisplay();
            Clipboard clipboard = new Clipboard(display);
            clipboard.setContents(new String[] {copyMenuClipboardText_}, new Transfer[] {TextTransfer.getInstance()});
            clipboard.dispose();
        }
    }

    protected void handleColumnSelect(SelectionEvent selectionEvent) {
        // selection event on one of the tables columns causes table to be sorted
        Widget w = selectionEvent.widget;
        TableColumn[] cols = table_.getColumns();
        for (int i=0; i 0) deselectAllOnWidget();
        } else {
            int [] swtIndexes = table_.getSelectionIndices();
            for (int i=0; imodelIndexLowerBound by an increment of amount.
     */
    private void adjustModelIndexes (int modelIndexLowerBound, int amount) {
        if (sortingCol_ == -1) {
            for (int i=modelIndexLowerBound, size=sortPermutation_.size(); i= modelIndexLowerBound) setPermIndex(i, val+amount);
            }
        }
    }

    /**
     * Returns the integer value in the permutation array at index i
     */
    private int getPermIndex (int i) {
        return ((Integer)sortPermutation_.get(i)).intValue();
    }

    /**
     * Sets the value in the permutation array at index i to value
     */
    private void setPermIndex (int i, int value) {
        sortPermutation_.set(i, new Integer(value));
    }

    /**
     * Adds a new SWT table item and keeps the sortPermutations
     * array up to date.
     *
     * @param swtIndex    the row index of the SWT table
     * @param modelIndex  the row index of the widget model
     * @return newly created TableItem
     */
    private TableItem newSWTRow (int swtIndex, int modelIndex) {
        sortPermutation_.add(swtIndex, new Integer(modelIndex));
        TableItem item = new TableItem (table_, SWT.NULL, swtIndex); 
        callItemCreated(item);
        return item;
    }    

    /**
     * @see at.spardat.xma.mdl.UIDelegateClient#getWModel()
     */
    public WModel getWModel() {
        return wModel_;
    }

    // see at.spardat.xma.mdl.UIDelegateClient.createControl()
    public Object createControl(Object parent) {
        if(!(parent instanceof Composite)) throw new IllegalArgumentException("parent must be a composite");
        Composite parentComp = (Composite)parent;
        Table table;
        if(wModel_.isMultiSelect()) {
            table = new Table(parentComp, SWT.MULTI|SWT.BORDER|SWT.FULL_SELECTION);
        } else {
            table = new Table(parentComp, SWT.SINGLE|SWT.BORDER|SWT.FULL_SELECTION);
        }
        table.setHeaderVisible(true);
        table.setLinesVisible(true);
        int cols = wModel_.getColumnCount();
        for(int i=0;i deltaX)
                return columnIndex;
            columnIndex++;
        }
        return columnIndex - 1;
    }

    /**
     * @see at.spardat.xma.mdl.UIDelegateClient#isUIAttached()
     */
    public boolean isUIAttached() {
        return table_ != null;
    }

    /**
     * Requirements on the attached SWT table are:
     * 
    *
  • The number of visible columns in the model must match the number of columns of the SWT table. *
  • If style SWT.CHECK or SWT.MULTI is set, the table model must be * constructed with style S_MULTI_SELECT. *
* * @see at.spardat.xma.mdl.UIDelegateClient#attachUI(java.lang.Object, java.lang.Object) */ public void attachUI (Object control, Object label) throws AttachmentExceptionClient { if (isUIAttached()) throw new IllegalStateException(); Table ta = null; ta = attachUIInternal(control); int style = ta.getStyle(); int numSWTCols = ta.getColumnCount(); boolean tableIsMulti = (style & SWT.CHECK) != 0 || (style & SWT.MULTI) != 0; if (tableIsMulti != wModel_.isMultiSelect()) throw new AttachmentExceptionClient ("SWT table and model selection cardinality does not match."); /** * set up the mapping between model and swt columns */ swtCol2ModelCol_ = new int[columnCount_]; // could be shorter, but who cares. modelCol2SwtCol_ = new int[columnCount_]; int j = 0; for (int i=0; i0) copyMenuItem_ = ta.getMenu().getItem(0); } else { throw new AttachmentExceptionClient ("TableDirect must be attached to a SWT-table or Nebula TableCombo"); } return ta; } /** * @see at.spardat.xma.mdl.UIDelegateClient#getUIControl() */ public Object getUIControl() { if (!isUIAttached()) throw new IllegalStateException (); return table_; } /** * @see at.spardat.xma.mdl.UIDelegateClient#getUILabel() */ public Object getUILabel() { if (!isUIAttached()) throw new IllegalStateException (); return null; } /** * @see at.spardat.xma.mdl.UIDelegateClient#detachUI() */ public void detachUI() { if (!isUIAttached()) return; updatingUI_ = true; try { enabled_=table_.getEnabled(); table_ = null; } finally { updatingUI_ = false; } } /** * This method first removes all rows from the SWT table. It * created as many SWT rows as there are rows in the widget model * using the right sort order. */ private void rows2UI () { table_.removeAll(); createUnsortedPermutation(); // sort sort (); // create the SWT rows createSWTRows(); } /** * Grabs the selection information from the model and updates the UI. */ private void selection2UI () { if (checkedSelection()) { // iterate over the SWT table and correct every check box for (int i=0, size=table_.getItemCount(); i 0){ Image image = null; try { short valueShort = Short.parseShort(a.toString()); if(valueShort == 0) text = ""; image = ((PageClient)wModel_.getPage()).getComponent().getImage(valueShort); } catch (NumberFormatException e) { } if (image != null) ti.setImage(i, image); else ti.setText(i, text); }else{ ti.setText(i, text); } if(wModel_.wm2UIlistener_ != null){ //call an registered listener wModel_.wm2UIlistener_.model2UIEvent(tr, ti, modelColumn, i); } } short imageId = (short) tr.getImageId(); if (imageId > 0) { // set image Image image = ((PageClient)wModel_.getPage()).getComponent().getImage(imageId); if (image != null) ti.setImage(image); } } /** * Creates a sort permutation in instance variable sortPermutation * that maps the SWT and model indices one to one. */ private void createUnsortedPermutation () { sortPermutation_ = new ArrayList (wModel_.size()); for (int i=0, size=wModel_.size(); isort-calls. */ protected void sortNatural () { if (!isUIAttached()) return; int topIndex = table_.getTopIndex(); if (sortingCol_ != -1) { sortingCol_ = -1; ascending = true; rows2UI(); selection2UI(); table_.setTopIndex(topIndex); // restore top index //erease the old sort indicator actualizeSortIndicator2UI(); } } /** * Sorts the table. Physically, the sort permutation in instance * variable sortPermutation is changed. */ private void sort () { if (sortingCol_ != -1 && allCellsInColumnOfSameType(sortingCol_)) { Collator collator = Collator.getInstance (getLocale()); collator.setStrength (Collator.SECONDARY); // todo parametrize this RowComparator cmp = new RowComparator (wModel_.table_, sortingCol_, ascending, collator,wModel_.getColumn(sortingCol_).getComparator()); Collections.sort (sortPermutation_, cmp); } } /** * Gets the locale from the attached widget */ private Locale getLocale () { return ((PageClient)wModel_.getPage()).getComponent().getSession().getContext().getLocale(); } /** * Determines if all Atoms in column colIndex are of the same * type or null. Only such columns are sortable. * * @param colIndex zero based index of a column in the model. */ private boolean allCellsInColumnOfSameType (int colIndex) { byte type = Types.FIRST-1; for (int i=0, size=wModel_.table_.size(); iTableItem that belongs to the row at * index modelIndex in the widget model. */ TableItem getTableItemForModelRowIndex (int modelIndex) { return table_.getItem(modelIndex2SwtIndex(modelIndex)); } /** * Invariant not indended to be used in production */ private void debugInvariant () { if (isUIAttached()) { // check the permutations array if (sortPermutation_.size() != wModel_.size()) throw new RuntimeException (); for (int i=0, size=sortPermutation_.size(); i wModel_.size()) throw new RuntimeException ("wrong model index " + modelIndex); } } } /** * Invariant which should also be checked in production code */ private void realInvariant () { // number of rows in the table must be equal to the number of rows in the model if (isUIAttached()) { if (table_.getItemCount() != wModel_.size()) { throw new RuntimeException ("table size mismatch, SWT: " + table_.getItemCount() + ", model: " + wModel_.size()); } } } /** * @see at.spardat.xma.mdl.UIDelegateClient#isEnabled() */ public boolean isEnabled () { if (isUIAttached()) { //always take the state from the widget (if it was set directly on it) as this is the old behavior enabled_ = table_.isEnabled(); } return enabled_; } /** * @see at.spardat.xma.mdl.UIDelegateClient#setEnabled(boolean) */ public void setEnabled (boolean what) { enabled_ = what; if (isUIAttached()) { table_.setEnabled(what); } } /** * @see at.spardat.xma.mdl.UIDelegateClient#isEditable() */ public boolean isEditable () { return editable_; } /** * @see at.spardat.xma.mdl.UIDelegateClient#setEditable(boolean) */ public void setEditable (boolean what) { editable_ = what; } /** * Not implemented - does nothing */ public void setErrorColor (boolean inError) { } /** * To compare two entries of the sortPermutation instance variable * * @author YSD, 27.04.2003 17:22:49 */ public class RowComparator implements Comparator { /** * Constructor * * @param table the TransAtomTable of the widget model that holds the rows * @param sortingCol index of the column which determines sort order * @param ascending true if sorting is in ascending order * @param collator used to sort strings */ public RowComparator (TransAtomTable table, int sortingCol, boolean ascending, Collator collator, AtomComparator comparator) { table_ = table; sortingCol_ = sortingCol; ascending_ = ascending; collator_ = collator; comparator_ = comparator; } /** * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ public int compare (Object o1, Object o2) { Integer i1 = (Integer)o1; Integer i2 = (Integer)o2; Atom a1 = table_.get(i1.intValue(), sortingCol_); Atom a2 = table_.get(i2.intValue(), sortingCol_); int cmpVal; // first, treat special case if Atoms are null if (a1 == null && a2 == null) cmpVal = 0; else if (a1 == null) cmpVal = -1; else if (a2 == null) cmpVal = 1; else if (comparator_ != null){ cmpVal = comparator_.compare(a1, a2); } else if (a1.getType() == Types.T_STRING) { cmpVal = collator_.compare(a1.toString(), a2.toString()); } else cmpVal = a1.compareTo(a2); return ascending_ ? cmpVal : cmpVal * -1; } private TransAtomTable table_; private int sortingCol_; private boolean ascending_; /** * for string sorting */ private Collator collator_; /** * The XMATableColumns custom comparator */ private AtomComparator comparator_; } /** * Sets the sort indicators at the table headers, * only if showSortIndicator_ is true. * @since version_number * @author S3460 */ private void actualizeSortIndicator2UI(){ if(showSortIndicator_){ ComponentClient component = ((PageClient) wModel_.getPage()).getComponent(); TableColumn[] cols = table_.getColumns(); for (int i = 0; i < cols.length; i++) { TableColumn column = cols[i]; Image image = null; if(getSortingColumn()>=0&&modelCol2SwtCol_[getSortingColumn()] == i){ if(isSortingColumnAscending()){ image = component.getImage(ARROW_UP_ICON); }else{ image = component.getImage(ARROW_DOWN_ICON); } }else{ image = component.getImage(ARROW_EMPTY_ICON); } column.setImage(image); } } } /** * @return Returns the ascending. */ boolean isSortingColumnAscending() { return ascending; } /** * @return Returns the sortingCol_. */ int getSortingColumn() { return sortingCol_; } /** * @return Returns the showSortIndicator_. */ boolean hasSortIndicator() { return showSortIndicator_; } /** * @param showSortIndicator_ The showSortIndicator_ to set. */ void setSortIndicator(boolean showSortIndicator) { this.showSortIndicator_ = showSortIndicator; } /** * Set the external sorter which will be used for sorting columns instead of the internal * sorting implementation of the table. * @since 3.2.0 * @author gub */ void setExternalSorter(TableExternalSorterClient externalSorter) { externalSorter_ = externalSorter; } /** * Execute callback. * * @param item */ protected void callItemCreated(TableItem item) { PageClient pageClient = (PageClient)wModel_.getPage(); if (pageClient != null) { pageClient.itemCreated(item); } } /** * Returns the model's TableRow to the given TableItem. * @param uiTableItem * @return TableRow for the given TableItem * @since version_number * @author S3460 */ static TableRow row2Item(TableItem uiTableItem){ Table table = uiTableItem.getParent(); int swtIndex = table.indexOf(uiTableItem); TableUIDelegateClient uiDelegate = (TableUIDelegateClient) table.getData(); int modelIndex = uiDelegate.swtIndex2ModelIndex(swtIndex); return uiDelegate.wModel_.getRow(modelIndex); } /** * Deselects all selected items on the widget */ protected void deselectAllOnWidget() { table_.deselectAll(); } /** * Sets Selection of SWT widget */ protected void setSelectionOnWidget(int[] selIndexes) { if (selIndexes.length > 0) { deselectAllOnWidget(); } table_.setSelection (selIndexes); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy