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

at.spardat.xma.mdl.list.ListWM Maven / Gradle / Ivy

The 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
 *******************************************************************************/

/*
 * Created on 04.11.2003
 *
 *
 *
 */
package at.spardat.xma.mdl.list;

import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import at.spardat.enterprise.exc.SysException;
import at.spardat.enterprise.fmt.AParseException;
import at.spardat.enterprise.fmt.IFmt;
import at.spardat.enterprise.util.Types;
import at.spardat.xma.mdl.Atom;
import at.spardat.xma.mdl.ModelChangeEvent;
import at.spardat.xma.mdl.NewModelEvent;
import at.spardat.xma.mdl.NewModelEventFactory;
import at.spardat.xma.mdl.Notification;
import at.spardat.xma.mdl.WModel;
import at.spardat.xma.mdl.util.DNode;
import at.spardat.xma.mdl.util.TransAtomTable;
import at.spardat.xma.mdl.util.TransStringSet;
import at.spardat.xma.mdl.util.TransStringSet1;
import at.spardat.xma.mdl.util.TransStringSetN;
import at.spardat.xma.page.Page;
import at.spardat.xma.serializer.XmaInput;
import at.spardat.xma.serializer.XmaOutput;
import at.spardat.xma.test.TestUtil;
import at.spardat.xma.util.Assert;

/**
 * Widged model to represent a list of choises. It can be used with
 * the SWT-widgets Combo and List. The entries of the list have to be provided by the
 * programmer. All entries must by {@link Atom}s of the same type.
 * The supported types are T_STRING, T_BCD, T_DATE and T_TIMESTAMP.
 * There are convinience methods to use Java Strings directly.
 * These Strings are converted to Atoms of type T_STRING internally.
 * For domain values please use {@link ListDomWM}.
 *
 * @author s2877
 */
public class ListWM extends WModel implements IListWM {

    /**
     * Holds selection information.
     */
    TransStringSet                      selection_;

    /**
     * Two dimensional array of Atom objects managing the data of the table.
     * This table has one column.
     */
    TransAtomTable                      table_;

    /**
     * Disallow the entering of values not in the list of choices by the user.
     */
    boolean user_strict_ = true;

    /**
     * Constructs a ListWM.
     * The behaviour can be ajusted with the following styles
     * 
    *
  • {@link IListWM#S_MULTI_SELECT} *
  • {@link IListWM#S_NOT_STRICT} *
      * @param id a numeric id which identifies the WidgetModel within its Page. * @param pm reference to the enclosing Page * @param style one of the style-constants listed above or S_NULL. */ public ListWM(short id, Page pm, int style) { super(id, pm); if ((style & S_NOT_STRICT) != 0) user_strict_ = false; if ((style & S_MULTI_SELECT) != 0) selection_ = new TransStringSetN(); else selection_ = new TransStringSet1(); table_ = new TransAtomTable(1); } /* (non-Javadoc) * @see at.spardat.xma.mdl.Transactional#changed() */ public boolean changed() { return selection_.changed() || table_.changed(); } /* (non-Javadoc) * @see at.spardat.xma.mdl.Transactional#rollback() */ public void rollback() { selection_.rollback(); table_.rollback(); handle (new ListChangedEvent()); handle (new SelectionChangedEvent(false)); } /* (non-Javadoc) * @see at.spardat.xma.mdl.Transactional#commit() */ public void commit() { selection_.commit(); table_.commit(); } /* (non-Javadoc) * @see at.spardat.xma.mdl.WModel#handle(at.spardat.xma.mdl.ModelChangeEvent) */ public boolean handle(ModelChangeEvent event) { return event.execute(); } /* (non-Javadoc) * @see at.spardat.xma.mdl.list.IListWM#clear() */ public void clear() { table_.clear(); selection_.clear(); handle (new ListChangedEvent ()); handle (new SelectionChangedEvent (false)); } /* * @see at.spardat.xma.mdl.util.Descriptive#describe(at.spardat.xma.mdl.util.DNode) */ public void describe (DNode n) { super.describe(n); n.app("user_strict", user_strict_).comma(); n.app("isMultiSel", isMultiSelect()).comma(); DNode sel = new DNode(n, "selection: "); sel.app(selection_); DNode table = new DNode(n, "listData: "); table.app(table_); } /* (non-Javadoc) * @see at.spardat.xma.mdl.WModel#randomlyChange() */ public void randomlyChange() { if (Assert.ON) { int change = TestUtil.randomInt(0, 8); switch (change) { case 0: // select a random entry if(size()>0) { select(getEntry(TestUtil.randomInt(0, size()-1)).toString()); } break; case 1: // deselect a random entry if(size()>0) { deselect(getEntry(TestUtil.randomInt(0, size()-1)).toString()); } break; case 2: // deselect all deselectAll(); break; case 3: // select a key randomly choosen select (TestUtil.randomString(TestUtil.randomInt(0, 3))); break; case 4: // randomly add an entry if(!this.isUserStrict()){ add(new Atom(TestUtil.randomString(1,64))); } else { add(TestUtil.randomString(1,64),new Atom(TestUtil.randomString(1,64))); } break; case 5: // randomly insert an entry if(size()>0){ if(!isUserStrict()){ add(TestUtil.randomInt(0,size()-1),new Atom(TestUtil.randomString(1,64))); } else { add(TestUtil.randomInt(0,size()-1),TestUtil.randomString(1,64), new Atom(TestUtil.randomString(1,64))); } } break; case 6: // update an entry if (size() > 0) { int index = TestUtil.randomInt(0, size()-1); if(!isUserStrict()){ replace(index,new Atom(TestUtil.randomString(1,64))); } else { replace(index,TestUtil.randomString(1,64), new Atom(TestUtil.randomString(1,64))); } } break; case 7: // delete an entry if (size() > 0) { remove(TestUtil.randomInt(0, size()-1)); } break; case 8: // randomly add an entry if(this.isUserStrict()){ add(TestUtil.randomString(1,64),new Atom(TestUtil.randomString(1,64))); } break; } } } /* (non-Javadoc) * @see at.spardat.xma.mdl.WModel#equalsCS(at.spardat.xma.mdl.WModel, int) */ public void equalsCS(WModel mServer, int syncPoint) { if (Assert.ON) { ListWM mS = (ListWM) mServer; // the selection must always be the same if (!selection_.equals(mS.selection_)) throw new RuntimeException(); // the tables must match if (!table_.equals(mS.table_)) throw new RuntimeException(); } } /* (non-Javadoc) * @see at.spardat.xma.mdl.WModel#estimateMemory() */ public int estimateMemory() { return 200 + table_.size()*50; } /** * Checks if entry matches the supported types and the type of the * allready added entries. * @param entry to check its type * @throws SysException if the type of the entry does not match the type * of allready existing entries or does not match the supported types. */ private void checkType(Atom entry) { if(table_.size()==0) { byte type = entry.getType(); if(type!=Types.T_STRING && type!=Types.T_BCD && type!=Types.T_DATE && type!=Types.T_TIMESTAMP &&type!=Types.T_BOOLEAN) { throw new SysException("type not supported: "+Atom.type2String(type)); } } else { byte type = table_.get(0,0).getType(); if(type!=entry.getType()) { throw new SysException("all entrys must be of the same type"); } } } /** * Checks if the allready containd entries are atoms of type T_STRING. * @param entry * @throws SysException if the list model allready contains entries of different * types than T_STRING. */ private void checkType(String entry) { if(table_.size()<0) { byte type = table_.get(0,0).getType(); if(type!=Types.T_STRING) { throw new SysException("all entrys must be of the same type"); } } } /* (non-Javadoc) * @see at.spardat.xma.mdl.list.IListWM#add(at.spardat.xma.mdl.Atom) */ public void add(Atom entry) { checkType(entry); boolean added = table_.add(entry.toString(),new Atom[]{entry}); if(added) { handle(new ListItemAddedEvent(table_.indexOf(entry.toString()))); } } /** * Inserts an entry into the list at the specified position and associates it with a key. * All selection and entry related methods then work with the key: * contains(), indexOf(), remove(), deselect(), select(), getSelected(), etc. * * * @param key to add * @param entry to add * @see at.spardat.xma.mdl.list.IListWM#add(java.lang.String,at.spardat.xma.mdl.Atom) */ public void add(int index,String key, Atom entry) { if(!isUserStrict()){ throw new IllegalStateException("Programming error: adding of key-value pairs is only allowed if the ListWM is strict!"); } checkType(entry); boolean added = table_.add(index, key,new Atom[]{entry}); if(added) { handle(new ListItemAddedEvent(table_.indexOf(key))); } } /** * Inserts an entry into the list at the specified position and associates it with a key. * All selection and entry related methods then work with the key: * contains(), indexOf(), remove(), deselect(), select(), getSelected(), etc. * This method can only be used if the model has the style strict, otherwise an exception is thrown! * * @param key to add * @param entry to add * @see at.spardat.xma.mdl.list.IListWM#add(java.lang.String,at.spardat.xma.mdl.Atom) */ public void add(int index,String key, String entry) { this.add(index, key, new Atom(entry)); } /** * Adds an entry to the list and associates it with a key. * The entry is appended at the end of the selection list. * All selection and entry related methods then work with the key: * contains(), indexOf(), remove(), deselect(), select(), getSelected(), etc. * This method can only be used if the model has the style strict, otherwise an exception is thrown! * * @param key to add * @param entry to add * @see at.spardat.xma.mdl.list.IListWM#add(java.lang.String,at.spardat.xma.mdl.Atom) */ public void add(String key, Atom entry) { this.add(size(),key, entry); } public void add(String entry) { checkType(entry); boolean added = table_.add(entry,new Atom[]{new Atom(entry)}); if(added) { handle(new ListItemAddedEvent(table_.indexOf(entry))); } } /** * Adds an entry to the list and associates it with a key. * The entry is appended at the end of the selection list. * All selection and entry related methods then work with the key: * contains(), indexOf(), remove(), deselect(), select(), getSelected(), etc. * This method can only be used if the model has the style strict, otherwise an exception is thrown! * * @param key to add * @param entry to add * @see at.spardat.xma.mdl.list.IListWM#add(java.lang.String, java.lang.String) */ public void add(String key, String entry) { this.add(key, new Atom(entry)); } /** * Adds all the key-value pairs from the map the list. * The entries are appended at the end of the list. * This method iterates over the Map and calls: * at.spardat.xma.mdl.list.IListWM#add(java.lang.String, java.lang.String). * * The keys in the Map have to be of the type String, the values have to be of the type String or Atom. * As the iteration order of a HashMap is undefined, it might be advisable to use a TreeMap or a LinkedHashMap. * * All selection and entry related methods then work with the keys: * contains(), indexOf(), remove(), deselect(), select(), getSelected(), etc. * This method can only be used if the model has the style strict, otherwise an exception is thrown! * * @param map -which is iterated * @see at.spardat.xma.mdl.list.IListWM#add(Map map) */ public void add(Map map) { Set keys = map.keySet(); for (Iterator iterator = keys.iterator(); iterator.hasNext();) { String key = (String) iterator.next(); Object entry = map.get(key); if(entry instanceof String){ this.add(key, new Atom((String)entry)); } else if (entry instanceof Atom){ this.add(key, (Atom)entry); } else { throw new IllegalStateException("Programming error: the values in the map parameter are neither of the type String nor Atom!"); } } } /* (non-Javadoc) * @see at.spardat.xma.mdl.list.IListWM#add(int, at.spardat.xma.mdl.Atom) */ public void add(int index, Atom entry) { checkType(entry); boolean added = table_.add(index,entry.toString(),new Atom[]{entry}); if(added) { handle(new ListItemAddedEvent(index)); } } public void add(int index, String entry) { checkType(entry); boolean added = table_.add(index,entry,new Atom[]{new Atom(entry)}); if(added) { handle(new ListItemAddedEvent(index)); } } /* (non-Javadoc) * @see at.spardat.xma.mdl.list.IListWM#add(at.spardat.xma.mdl.Atom[]) */ public void add(Atom[] entries) { for(int i=0;i= size()) return; //do nothing //KWF 28.01.11 String key = table_.getKey(index); selection_.remove(key); //also remove it from the selection table_.remove(index); handle(new ListItemRemovedEvent(index)); } /* (non-Javadoc) * @see at.spardat.xma.mdl.list.IListWM#replace(int, at.spardat.xma.mdl.Atom) */ public void replace(int index, Atom newEntry) { checkType(newEntry); table_.remove(index); table_.add(index,newEntry.toString(),new Atom[]{newEntry}); handle(new ListItemChangedEvent(index)); } /** * */ public void replace(int index, String newEntry) { checkType(newEntry); table_.remove(index); table_.add(index,newEntry,new Atom[]{new Atom(newEntry)}); handle(new ListItemChangedEvent(index)); } /** * @see at.spardat.xma.mdl.list.IListWM#replace(int, java.lang.String, at.spardat.xma.mdl.Atom) * * Replaces an entry (key-value pair) in the list. The old entry at the * given index position is replaced by the entry given * as parameter. * This method can only be used if the model has the style strict, otherwise an exception is thrown! * * @param index the index of the entry to replace. * @param newKey the new key to insert. * @param newEntry the new entry to insert. */ public void replace(int index, String newKey, Atom newEntry) { if(!isUserStrict()){ throw new IllegalStateException("Programming error: adding of key-value pairs is only allowed if the ListWM is strict!"); } String key = table_.getKey(index); selection_.remove(key); //also remove it from the selection table_.remove(index); checkType(newEntry); boolean added = table_.add(index, newKey,new Atom[]{newEntry}); if(added) { handle(new ListItemChangedEvent(index)); } else { handle(new ListItemRemovedEvent(index)); //should not happen } } /** * @see at.spardat.xma.mdl.list.IListWM#replace(int, java.lang.String, java.lang.String) * * Replaces an entry (key-value pair) in the list. The old entry at the * given index position is replaced by the entry given * as parameter. * * This method can only be used if there were already entries added with add(key,entry) - otherwise an exception is thrown! * * @param index the index of the entry to replace. * @param newKey the new key to insert. * @param newEntry the new entry to insert. */ public void replace(int index, String newKey, String newEntry) { replace(index, newKey, new Atom(newEntry)); } /* (non-Javadoc) * @see at.spardat.xma.mdl.list.IListWM#contains(at.spardat.xma.mdl.Atom) */ public boolean contains(Atom entry) { return table_.containsKey(entry.toString()); } public boolean contains(String entry) { return table_.containsKey(entry); } /* (non-Javadoc) * @see at.spardat.xma.mdl.list.IListWM#size() */ public int size() { return table_.size(); } /* (non-Javadoc) * @see at.spardat.xma.mdl.ISelectable#select(java.lang.String) */ public void select(String key) { if(!isStrict() || table_.containsKey(key)) { boolean success = selection_.add (key); if (success) { handle (new SelectionChangedEvent (false)); } } } /** * Sets the selection of this ListWM to the given value. * If value is empty (null or ""), the selection is cleared. * @param value to select */ public void set(String value) { if(value!=null && value.length()>0) { select(value); } else { deselectAll(); } } /* (non-Javadoc) * @see at.spardat.xma.mdl.ISelectable#deselect(java.lang.String) */ public void deselect(String key) { selection_.remove (key); handle (new SelectionChangedEvent (false)); } /* (non-Javadoc) * @see at.spardat.xma.mdl.ISelectable#deselectAll() */ public void deselectAll() { selection_.clear(); handle (new SelectionChangedEvent (false)); } /* (non-Javadoc) * @see at.spardat.xma.mdl.ISelectable#isMultiSelect() */ public boolean isMultiSelect() { return selection_ instanceof TransStringSetN; } /* (non-Javadoc) * @see at.spardat.xma.mdl.ISelectable#getSelected() */ public String getSelected() { return selection_.getSome(); } /* (non-Javadoc) * @see at.spardat.xma.mdl.ISelectable#getSelection() */ public String[] getSelection() { return selection_.getAll(); } /* (non-Javadoc) * @see at.spardat.xma.mdl.ISelectable#getSelectionCount() */ public int getSelectionCount() { return selection_.size(); } /* (non-Javadoc) * @see at.spardat.xma.mdl.ISelectable#isSelected(java.lang.String) */ public boolean isSelected(String key) { return selection_.contains(key); } /* (non-Javadoc) * @see at.spardat.xma.mdl.ISelectable#isStrict() */ public boolean isStrict() { //every single selection model can be attached to an attrval -> not strict //multi selection models are allways strict return selection_ instanceof TransStringSetN; } /** * Returns if the user is allowed to enter values not in the list of choices. * @return true if the user can enter additional values */ public boolean isUserStrict() { return user_strict_; } /* (non-Javadoc) * @see at.spardat.xma.mdl.Synchronization#externalize(at.spardat.xma.serializer.XmaOutput, boolean) */ public void externalize(XmaOutput xo, boolean forceFull) throws IOException { // decide on what to write byte what = 0; boolean writeTable = forceFull || table_.changed(); boolean writeSel = forceFull || selection_.changed(); // externalize if (writeTable) what |= 1; if (writeSel) what |= 2; xo.writeByte("tableOrSel", what); if (writeTable) { // externalize table table_.externalize (xo, forceFull); } if (writeSel) { // externalize selection selection_.externalize (xo, forceFull); } } /* (non-Javadoc) * @see at.spardat.xma.mdl.Synchronization#internalize(at.spardat.xma.serializer.XmaInput) */ public void internalize(XmaInput in, List formattable) throws IOException, ClassNotFoundException { byte what = in.readByte(); boolean tableChanged = ((what & 1) != 0); boolean selChanged = ((what & 2) != 0); if (tableChanged) { table_.internalize(in, formattable); } if (selChanged) { selection_.internalize(in, formattable); } if (tableChanged) handle (new ListChangedEvent ()); if (selChanged || tableChanged) handle (new SelectionChangedEvent (false)); } /** * Notification event sent when one or more entries of the list might * have changed, removed or added without knowning the precise * reason of the change. */ class ListChangedEvent extends Notification { /** * Constructor * * @param wModel the widget model */ public ListChangedEvent () { super (ListWM.this, false); } } class ListItemAddedEvent extends Notification { int index; /** * @param destination * @param fromUI */ public ListItemAddedEvent(int index) { super(ListWM.this, false); this.index = index; } public int getIndex() { return index; } } class ListItemChangedEvent extends Notification { int index; /** * @param destination * @param fromUI */ public ListItemChangedEvent(int index) { super(ListWM.this, false); this.index = index; } public int getIndex() { return index; } } class ListItemRemovedEvent extends Notification { int index; /** * @param destination * @param fromUI */ public ListItemRemovedEvent(int index) { super(ListWM.this, false); this.index = index; } public int getIndex() { return index; } } /** * Notification event that the selection state has changed. */ class SelectionChangedEvent extends Notification { /** * Constructor */ public SelectionChangedEvent (boolean fromUI) { super (ListWM.this, fromUI); } } /** * Modificative event that sets an entirely new selection */ class NewSelectionEvent extends ModelChangeEvent { /** * Constructor * * @param selectedKeys the set of keys that are to be selected * @param fromUI indicates if the events origin is the UI or not */ public NewSelectionEvent (Collection selectedKeys, boolean fromUI) { super (ListWM.this, fromUI); selectedKeys_ = selectedKeys; } /** * Selects the provided keys. Invalid keys (that are not in the table) are ignored. * * @see at.spardat.xma.mdl.ModelChangeEvent#execute() */ public boolean execute() { TransStringSet sel = ((ListWM)wModel_).selection_; TransAtomTable table = ((ListWM)wModel_).table_; sel.clear(); Iterator iter = selectedKeys_.iterator(); while (iter.hasNext()) { String key = (String) iter.next(); if(!isStrict() || table.containsKey(key)) { sel.add(key); } } return true; } private Collection selectedKeys_; } /** * Event class used to notify the dynamic registration of a new ListWM. * @author gub * @since 2.1.0 * @see Page#addWModel(WModel) */ public static class NewListWMEvent extends NewModelEvent { int style; /** empty contructor for deserialization */ public NewListWMEvent() {} /** * constructor which initializes dataSource and style * @param style one of the style-constants listed in {@link IListWM}. */ public NewListWMEvent(int style) { this.style=style; } // see at.spardat.xma.mdl.NewModelEvent.getType() public byte getType() { return NewModelEventFactory.ListWM; } // see at.spardat.xma.mdl.NewModelEvent.createModel() public WModel createModel(short id,Page page) { return new ListWM(id,page,style); } // see at.spardat.xma.mdl.NewModelEvent.serialize() public void serialize(XmaOutput out) throws IOException { super.serialize(out); out.writeInt("style",style); } // see at.spardat.xma.mdl.NewModelEvent.deserialize() public void deserialize(XmaInput in) throws IOException, ClassNotFoundException { super.deserialize(in); style=in.readInt(); } } // see at.sparda.xma.mdl.WModel.createNewModelEvent() public NewModelEvent createNewModelEvent() { int style = S_NULL; if(isMultiSelect()) style|=S_MULTI_SELECT; if(!isUserStrict()) style|=S_NOT_STRICT; return new NewListWMEvent(style); } public boolean isValid() { // check only mandatory flag IFmt fmt = getFmtInternal(); if (fmt != null) { try { fmt.checkMandatory(getSelected()); } catch (AParseException ape) { return false; } } return true; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy