Package smilehouse.gui.html.fieldbased

Source Code of smilehouse.gui.html.fieldbased.ContainerEditor$ContainingFieldIterator

/* OpenSyncro - A web-based enterprise application integration tool
* Copyright (C) 2008 Smilehouse Oy, support@opensyncro.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package smilehouse.gui.html.fieldbased;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import smilehouse.gui.html.fieldbased.editor.AbstractEditor;
import smilehouse.gui.html.fieldbased.editor.EditorResources;
import smilehouse.gui.html.fieldbased.editor.WebEditor;
import smilehouse.tools.template.Template;

/**
* A special kind of editor that can modify a Collection-type property. The Collection objects are
* treated as rows and each row has columns, which contain fields for modifying the Collection
* object's properties.
*/
public class ContainerEditor implements WebEditor {
    //  template read in the constructor
    protected Template baseTemplate;

    //  true if delete button is enabled
    protected boolean delete;
    //  the labelkey used to get the text for the delete button
    protected String deleteLabel;

    protected boolean clone;
    protected String cloneLabel;
   
   
    protected boolean add;//true if add button is enabled
    protected String addLabel;//the labelkey used to get the text for the add button
    protected String confirmLabel; //the labelkey used to get the text shown for confirming the delete
   
   
    //child class given when enabling add-button. new objects are created
    //with childClass.newInstance()
    private Class childClass;

    //  true if move button's is enabled (used to change the order of the
    // objects)
    protected boolean move;
    protected String moveLabel; //the labelkey used to get the text for the buttons column's header
    protected String upImgSrc; //src-attributes value for the up-button's image
    protected String upImgAltLabel; //the labelkey used to get the alt-text for the up button
    protected String doImgSrc; //src-attributes value for the down-button's image
    protected String doImgAltLabel; //the labelkey used to get the alt-text for the down button

   

    /**
     * Creates a containereditor with the default settings.
     */
    public ContainerEditor() {
        this.baseTemplate = Template.load(
            ContainerEditor.class
                .getResourceAsStream("editor/defaulttemplates/containereditor.html"),
            AbstractEditor.DEFAULT_TEMPLATE_ENCODING);
        this.delete = false;
        this.deleteLabel = null;
        this.add = false;
        this.addLabel = null;
        this.move = false;
        this.clone=false;
        this.cloneLabel=null;
    }

    /**
     * Creates a containereditor with the given template.
     */
    public ContainerEditor(Template template) {
        this.baseTemplate = template;
        this.delete = false;
        this.add = false;
        this.move = false;
        this.clone=false;
    }


    public ContainerEditor enableDelete(String deleteLabel, String confirmLabel) {
        this.delete = true;
        this.deleteLabel = deleteLabel;
        this.confirmLabel = confirmLabel;
        return this;
    }
   
   /***********************************************************************************************
     * Enables cloning of items in the collection. A clone button will be added for each row item in
     * the editor.
     *
     * @param classToClone The class of the object you want to clone. The class must implement Cloneable.
     * @param cloneLabel The labelkey used for the clone button
     * @return Returns itself
     * @exception CloneNotSupportedException - if classToClone does not implement Cloneable interface
     */

    public ContainerEditor enableClone(Class classToClone, String cloneLabel) throws CloneNotSupportedException {
     
      //Does the class we want to clone implement Cloneable interface?
       if(Cloneable.class.isAssignableFrom(classToClone)){
         this.clone=true;
           this.cloneLabel=cloneLabel;
           return this;
        }
     
      throw new CloneNotSupportedException("Class does not implement Cloneable interface");
    }

    /**
     * Enables deletion of childs from the collection. A delete button is added as the last column
     * of the row. NOTE: the iterator of the modifier collection property must support the
     * remove-method.
     *
     * @param deleteLabel The labelkey used to retrieve the text for the delete button.
     * @return Returns itself
     */
    public ContainerEditor enableDelete(String deleteLabel) {
        return enableDelete(deleteLabel, null);
    }

    /***********************************************************************************************
     * Enables adding of childs to the collection. An add button will be added to the editor as the
     * last row. NOTE: the given child class must have a constructor without parameters.
     *
     * @param childClass The item object class in the collection. For example, you might have a
     *        collection of String-objects, so you would call this method with
     *        enableAdd(String.class, "addLabelKey").
     * @param addLabel The labelkey used for the add-button.
     * @return Returns itself
     * @exception IllegalAccessException - if the class or its nullary constructor is not
     *            accessible.
     * @exception InstantiationException - if this Class represents an abstract class, an interface,
     *            an array class, a primitive type, or void; or if the class has no nullary
     *            constructor; or if the instantiation fails for some other reason.
     */
    public ContainerEditor enableAdd(Class childClass, String addLabel) throws InstantiationException,
            IllegalAccessException {
        //check that we can create new childs
        childClass.newInstance();
        //precondition passed
        this.add = true;
        this.childClass = childClass;
        this.addLabel = addLabel;
        return this;

    }

    /**
     * Enable changing the order of the collection's items. To support this the Collection must
     * implement the java.util.List-interface.
     *
     * @param moveLabel the labelkey used to get the text for the buttons column's header
     * @param upImgSrc src-attributes value for the up-button's image
     * @param upImgAltLabel the labelkey used to get the alt-text for the up button
     * @param doImgSrc src-attributes value for the down-button's image
     * @param doImgAltLabel the labelkey used to get the alt-text for the down button
     * @return Returns itself
     */
    public ContainerEditor enableMove(String moveLabel,
                           String upImgSrc,
                           String upImgAltLabel,
                           String doImgSrc,
                           String doImgAltLabel) {
        this.move = true;
        this.moveLabel = moveLabel;
        this.upImgSrc = upImgSrc;
        this.upImgAltLabel = upImgAltLabel;
        this.doImgSrc = doImgSrc;
        this.doImgAltLabel = doImgAltLabel;
        return this;
    }




    /***********************************************************************************************
     *
     * @return the html-representation of this editor.
     * 
     */
    public String getEditor(EditorResources editorResources) {
        Template template = baseTemplate.copyStructure();
        template.setVariable("description", editorResources.getDescription());


        Collection columnFields = getColumnFields(editorResources);
        int cols = columnFields.size();
        if(delete)
            cols++;
        if(move)
            cols++;
        if(clone)
          cols++;
        template.setVariable("cols", "" + cols);

        //write headers
        Template header = template.getBlock("header");
        Template headerColumn = header.getBlock("column");
        for(Iterator iter = columnFields.iterator(); iter.hasNext();) {
            FieldImpl column = (FieldImpl) iter.next();
            headerColumn.setVariable("description", column.getDescription());
            headerColumn.write();
        }
        if(move) {
            headerColumn.setVariable("description", editorResources.getResource().getLabel(
                this.moveLabel));
            headerColumn.write();
        }
        if(delete) {
            headerColumn.setVariable("description", editorResources.getResource().getLabel(
                this.deleteLabel));
            headerColumn.write();
        }
        if(clone) {
          headerColumn.setVariable("description", editorResources.getResource().getLabel(
                    this.cloneLabel));
            headerColumn.write();
        }
        header.write();




        //write field editors
        ContainingFieldIterator allFields = getAllFields(editorResources);
        int rowNum = 0;
        String rowClass = "ttrow1";
        Template row = template.getBlock("row");
        Template rowColumn = row.getBlock("column");
        while(allFields.hasNext()) {
            FieldImpl column = (FieldImpl) allFields.next();

            // set css zeebra-class
            rowColumn.setVariable("rowClass", rowClass);

            //set editor
            rowColumn.setVariable("field", column.getEditor());
            rowColumn.write();
            //System.err.println("column id; "+column.getId());
            //      System.err.println("column readId: "+column.getReadId());
            //      System.err.println("column writeId: "+column.getWriteId());
            //      System.err.println("");

           
            //do row change
            if(allFields.lastColumnInRow()) {
             
                if(move) {
                    rowColumn.setVariable("rowClass", rowClass);
                    Template buttonB = rowColumn.getBlock("button");
                    if(rowNum != 0) {
                        buttonB.setVariable("id", editorResources.getWriteId() + "_up_" + rowNum);
                        buttonB.setVariable("src", this.upImgSrc);
                        buttonB.setVariable("description", ""
                                + editorResources.getResource().getLabel(this.upImgAltLabel));
                        buttonB.write();
                    }
                    if(!allFields.lastRow()) {
                        buttonB.setVariable("id", editorResources.getWriteId() + "_down_" + rowNum);
                        buttonB.setVariable("src", this.doImgSrc);
                        buttonB.setVariable("description", ""
                                + editorResources.getResource().getLabel(this.doImgAltLabel));
                        buttonB.write();
                    }
                    rowColumn.write();
                }
                if(delete) {
                    //write delete button: TODO: support for changing the buttons...
                    rowColumn.setVariable("rowClass", rowClass);
                    Template buttonB = rowColumn.getBlock("deletebutton");
                    buttonB.setVariable("id", editorResources.getWriteId() + "_delete_" + rowNum);
                    buttonB.setVariable("description", ""
                            + editorResources.getResource().getLabel(this.deleteLabel));
                    // Add a confirmation popup too if there's a label for it.
                    if(confirmLabel != null) {
                        Template confirmB = buttonB.getBlock("deleteconfirm");
                        confirmB.setVariable("confirmMessage", ""
                                + editorResources.getResource().getLabel(this.confirmLabel));
                        confirmB.write();
                    }

                    buttonB.write();
                    rowColumn.write();
                }
                if(clone){
                  rowColumn.setVariable("rowClass", rowClass);
                    Template buttonB = rowColumn.getBlock("deletebutton");
                    buttonB.setVariable("id", editorResources.getWriteId() + "_clone_" + rowNum);
                    buttonB.setVariable("description", ""
                            + editorResources.getResource().getLabel(this.cloneLabel));

                    buttonB.write();
                    rowColumn.write();
                }
               
                row.write();
                rowNum++;
                //set zeebra, note that we are counting from zero
               
                if(rowNum % 2 == 0)
                    rowClass = "ttrow1";
                else
                    rowClass = "ttrow2";
               
               
               
               
               
            }
        }
        //the last row must be written too
        row.write();

        //write possible add-button too
        if(add) {
            Template addB = template.getBlock("add");
            addB.setVariable("cols", "" + cols);
            addB.setVariable("id", editorResources.getWriteId() + "Add");
            addB.setVariable("description", editorResources.getResource().getLabel(this.addLabel));
            addB.write();
        }




        //AbstractEditor.writeEditorErrors(template, editorResources);

        template.write();
        return template.toString();
    }

    /**
     * @return true if any of the buttons have been pressed or any of the containing fields has been
     *         edited.
     */
    public boolean hasBeenEdited(EditorResources editorResources) {
        boolean edited = false;

        //check if add button pressed
        if(editorResources.getRequest().getParameter(editorResources.getReadId() + "Add") != null)
            return true;
        String a=editorResources.getReadId();
        String s=editorResources.getRequest().getParameter(a + "Clone");
         if(s != null)
            return true;

        //check if any of the containing fields has been edited
        ContainingFieldIterator allFields = getAllFields(editorResources);
        int rowNum = 0;
        while(allFields.hasNext()) {
            Field oneField = (Field) allFields.next();
            if(oneField.hasBeenEdited())
                return true;
            if(allFields.lastColumnInRow()) {
                //check if arrowup button pressed
                if(editorResources.getRequest().getParameter(
                    editorResources.getReadId() + "_up_" + rowNum + ".x") != null)
                    return true;
                //check if arrowdown button pressed
                if(editorResources.getRequest().getParameter(
                    editorResources.getReadId() + "_down_" + rowNum + ".x") != null)
                    return true;
                //check if delete button pressed
                if(editorResources.getRequest().getParameter(
                    editorResources.getReadId() + "_delete_" + rowNum) != null)
                    return true;

                rowNum++;
            }
        }
        return edited;

    }

    /**
     * Commits all valid edit's in this editor. Then modifies the collection if any of the buttons
     * were pressed (add,remove,move).
     */
    public boolean commit(EditorResources editorResources) {
        //first we try to commit all field edits
        ContainingFieldIterator allFields = getAllFields(editorResources);
        boolean someCommitted = false;
        while(allFields.hasNext()) {
            Field oneField = (Field) allFields.next();
            if(oneField.hasBeenEdited() && oneField.isEditValid()) {
                oneField.commit();
                someCommitted = true;
            }
        }

        //now we can try to modify the collection (if buttons are pressed)
        Collection col = (Collection) editorResources.getModelValue();

        //if add button pressed
        if(add
                && editorResources.getRequest().getParameter(editorResources.getReadId() + "Add") != null) {
            Object child = null;

            try {
                child = this.childClass.newInstance();
            } catch(Exception e) {
                /*
                 * this was checked when the add was enabled, let's still make sure that this
                 * doesn't silently fail.
                 */
                throw new RuntimeException(
                    "couldn't create a new child. The enableAdd should check this in configuration.");
            }
            List list = (List) col;
            list.add(child);

            ContainerFieldImpl cont = (ContainerFieldImpl) editorResources;
            List rows = cont.getRows();
            rows.add(new ContainerRow(rows.size(), child));

        }



        for(int i = 0; i < col.size(); i++) {
            //check if arrowup button pressed
            if(move
                    && editorResources.getRequest().getParameter(
                        editorResources.getReadId() + "_up_" + i + ".x") != null) {
                List list = (List) col;
                list.add(i - 1, list.remove(i));
                //update rows
                ContainerFieldImpl cont = (ContainerFieldImpl) editorResources;
                List rows = cont.getRows();
                rows.add(i - 1, rows.remove(i));

            }
            //check if arrowdown button pressed
            if(move
                    && editorResources.getRequest().getParameter(
                        editorResources.getReadId() + "_down_" + i + ".x") != null) {
                List list = (List) col;
                list.add(i + 1, list.remove(i));
                //update rows
                ContainerFieldImpl cont = (ContainerFieldImpl) editorResources;
                List rows = cont.getRows();
                rows.add(i + 1, rows.remove(i));
            }
            //check if delete button pressed
            if(delete
                    && editorResources.getRequest().getParameter(
                        editorResources.getReadId() + "_delete_" + i) != null) {
                Iterator it = col.iterator();
                int count = 0;
                while(it.hasNext() && count < i) {
                    it.next();
                    count++;
                }
                if(it.hasNext()) {
                    Object r = it.next();
                    col.remove(r);
                }
                //update rows
                ContainerFieldImpl cont = (ContainerFieldImpl) editorResources;
                List rows = cont.getRows();
                rows.remove(i);

            }
//          check if clone button was pressed
            if(clone && editorResources.getRequest().getParameter(
                        editorResources.getReadId() + "_clone_" + i) != null) {
                Iterator it = col.iterator();
                List list = (List) col;
                Object r=null;
                int count = 0;
               
                while(it.hasNext() && count < i) {
                    it.next();
                    count++;
                }
                Object newObject=null;
                if(it.hasNext()) {
                    r = it.next();
          try{
            Method objClone=r.getClass().getMethod("clone", (Class []) null);
            newObject=objClone.invoke(r, (Object[]) null);
          }
          catch(Exception e){
            //The object is supposed to have a clone method
            throw new RuntimeException(
                      "The class doesn't have a clone method");
          }
                    list.add(i + 1, newObject);
                   
                }
                //update rows
                ContainerFieldImpl cont = (ContainerFieldImpl) editorResources;
                List rows = cont.getRows();
        rows.add(new ContainerRow(rows.size(), newObject));

            }

        }

        return someCommitted;

    }

    /** @return true if all containing fields are valid. */
    public boolean isEditValid(EditorResources editorResources) {
        boolean valid = true;
        //check if any of the containing fields are invalid
        Iterator allFields = getAllFields(editorResources);
        while(allFields.hasNext()) {
            Field oneField = (Field) allFields.next();
            if(oneField.hasBeenEdited() && !oneField.isEditValid())
                return false;
        }
        return valid;
    }




    /**
     * methods that have to be in a webeditor, but are not really usefull with a containereditor.
     * ContainerEditor should be used with the ContainerFieldInfo, which knows not to use these
     * methods. So these methods are called only if the editor is misused.
     */
    public String validate(EditorResources editorResources) {
        throw new IllegalStateException("container_editor_should_be_used_with_containerfieldinfo");
    }

    /**
     * methods that have to be in a webeditor, but are not really usefull with a containereditor.
     * ContainerEditor should be used with the ContainerFieldInfo, which knows not to use these
     * methods. So these methods are called only if the editor is misused.
     */
    public boolean hasEditValue(EditorResources editorResources) {
        throw new IllegalStateException("container_editor_should_be_used_with_containerfieldinfo");
    }

    /**
     * methods that have to be in a webeditor, but are not really usefull with a containereditor.
     * ContainerEditor should be used with the ContainerFieldInfo, which knows not to use these
     * methods. So these methods are called only if the editor is misused.
     */
    public Object getEditValue(EditorResources editorResources) {
        throw new IllegalStateException("container_editor_should_be_used_with_containerfieldinfo");
    }


    /**
     * Private helper that creates the column fields from the column fieldinfo's
     */
    protected Collection getColumnFields(EditorResources editorResources) {
        ContainerFieldImpl containerField = (ContainerFieldImpl) editorResources;
        Collection columnFields = containerField.getColumnFields();
        return columnFields;
    }

    /**
     * Private helper that is used to iterate trough the editor. This includes all rows and each
     * column in every row.
     */
    protected ContainingFieldIterator getAllFields(EditorResources editorResources) {
        ContainerFieldImpl cont = (ContainerFieldImpl) editorResources;
        return new ContainingFieldIterator(cont);
    }


    /**
     * Private helper class that is used to iterate trough the editor. This includes all rows and
     * each column in every row.
     */
    class ContainingFieldIterator implements Iterator {
        ContainerFieldImpl field;

        int rowNum;
        int colNum;
        Iterator rows;
        Iterator cols;
        ContainerRow currentRow;

        public ContainingFieldIterator(ContainerFieldImpl field) {
            if(field==null)
                throw new NullPointerException("field cannot be null");
           
            this.field = field;
            this.rowNum = 0;
            this.colNum = 0;

            this.rows = field.getRows().iterator();
            this.cols = field.getColumnFields().iterator();
            if(rows.hasNext())
                this.currentRow = (ContainerRow) rows.next();
        }

        public boolean lastColumnInRow() {
            return (!cols.hasNext());
        }

        public boolean lastRow() {
            return (!rows.hasNext());
        }

        public boolean hasNext() {
            if(cols.hasNext() && this.currentRow != null)
                return true;
            if(rows.hasNext())
                return true;
            //no more cols or rows
            return false;
        }

        public Object next() {
            //do row change
            if(!cols.hasNext()) {
                this.currentRow = (ContainerRow) rows.next();//model changes
                rowNum++; //don't forget this,
                this.cols = field.getColumnFields().iterator();//go again through the columns for
                // the new row
                colNum = 0; //or this
            }
            //get the field
            ContainableField column = (ContainableField) cols.next();

            //finally set all the fancy stuff, which is why this iterator was built in the first
            // place
            column.setModel(currentRow.getBean());
            column.setWriteId(field.getWriteId() + "_row" + rowNum + "_col" + colNum);//"_"+columnResources.getId()+
            column.setReadId(field.getReadId() + "_row" + currentRow.getReadIndex() + "_col"
                    + colNum);//+"_"+columnResources.getId()

            colNum++;
            return column;
        }

        public void remove() {
            throw new RuntimeException("not implemented.");
        }
    }




}

TOP

Related Classes of smilehouse.gui.html.fieldbased.ContainerEditor$ContainingFieldIterator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.