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

com.inmethod.grid.common.AbstractGrid Maven / Gradle / Ivy

package com.inmethod.grid.common;

import java.util.Collection;
import java.util.Collections;
import java.util.List;

import javax.swing.tree.TreeModel;

import com.inmethod.grid.IGridColumn;
import com.inmethod.grid.IGridSortState;
import com.inmethod.grid.SizeUnit;
import com.inmethod.grid.datagrid.DataGrid;
import com.inmethod.grid.toolbar.AbstractHeaderToolbar;
import com.inmethod.grid.toolbar.AbstractToolbar;
import com.inmethod.grid.treegrid.TreeGrid;
import org.apache.wicket.Component;
import org.apache.wicket.MetaDataKey;
import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.attributes.AjaxCallListener;
import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
import org.apache.wicket.ajax.attributes.CallbackParameter;
import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
import org.apache.wicket.request.resource.PackageResourceReference;
import org.apache.wicket.resource.CoreLibrariesContributor;
import org.apache.wicket.util.lang.Args;
import org.apache.wicket.util.string.AppendingStringBuffer;
import org.apache.wicket.util.string.Strings;
import org.apache.wicket.util.visit.IVisit;
import org.apache.wicket.util.visit.IVisitor;

/**
 * Provides common functionality for {@link DataGrid} and {@link TreeGrid}.
 * 
 * @param 
 *            grid model object type
 * @param 
 *            row/item model object type
 * 
 * @author Matej Knopp
 */
public abstract class AbstractGrid extends Panel
{
	private static final long serialVersionUID = 1L;

	/**
	 * Creates new {@link AbstractGrid} instance
	 * 
	 * @param id
	 * @param model
	 * @param columns
	 */
	public AbstractGrid(String id, IModel model, List> columns)
	{
		super(id, model);

		setVersioned(false);

		columnsSanityCheck(columns);

		setOutputMarkupId(true);

		this.columns = columns;

		add(new Header("header"));

		Form form = new Form("form");
		add(form);

		WebMarkupContainer bodyContainer = new WebMarkupContainer("bodyContainer")
		{
			private static final long serialVersionUID = 1L;

			@Override
			protected void onComponentTag(ComponentTag tag)
			{
				super.onComponentTag(tag);
				if (getContentHeight() > 0 && getContentHeightSizeUnit() != null)
				{
					tag.put("style", "height:" + getContentHeight() +
						getContentHeightSizeUnit().getValue());
				}
			}
		};
		form.add(bodyContainer);
		bodyContainer.setOutputMarkupId(true);

		bodyContainer.add(new Label("firstRow", new EmptyRowModel())
                 .setEscapeModelStrings(false));

		add(topToolbarContainer = new RepeatingView("topToolbarContainer"));
		add(bottomToolbarContainer = new RepeatingView("bottomToolbarContainer"));
		add(headerToolbarContainer = new RepeatingView("headerToolbarContainer"));

		add(new Behavior()
		{
			private static final long serialVersionUID = 1L;

			@Override
			public void renderHead(Component component, IHeaderResponse response)
			{
				super.renderHead(component, response);
				// since javascript can be rendered at the tail
				// of HTML document, do not initialize data grid
				// component until "DOM ready" event.
				response.render(OnDomReadyHeaderItem.forScript(getInitializationJavascript()));
			}
		});

		columnState = new ColumnsState(columns);

		add(submitColumnStateBehavior);
	}

	@SuppressWarnings("unchecked")
	public Form getForm()
	{
		return (Form)get("form");
	}

	/**
	 * Checks whether the column is a valid grid column
	 * 
	 * @param column
	 */
	protected void columnSanityCheck(IGridColumn column)
	{
		String id = column.getId();
		if (Strings.isEmpty(id))
		{
			throw new IllegalStateException("Column id must be a non-empty string.");
		}
		for (int i = 0; i < id.length(); ++i)
		{
			char c = id.charAt(i);
			if (!Character.isLetterOrDigit(c) && c != '.' && c != '-' && c != '_')
			{
				throw new IllegalStateException("Column id contains invalid character(s).");
			}
		}
		if (column.isResizable() && column.getSizeUnit() != SizeUnit.PX)
		{
			throw new IllegalStateException("Resizable columns size must be in the PX unit.");
		}
	}

	/**
	 * Checks whether the columns have proper values.
	 * 
	 * @param columns
	 */
	private void columnsSanityCheck(List> columns)
	{
		for (int i = 0; i < columns.size(); ++i)
		{
			IGridColumn column = columns.get(i);
			columnSanityCheck(column);
		}
		for (int i = 0; i < columns.size(); ++i)
		{
			IGridColumn column = columns.get(i);

			for (int j = 0; j < columns.size(); ++j)
			{
				if (i != j)
				{
					IGridColumn otherColumn = columns.get(j);
					if (column.getId().equals(otherColumn.getId()))
					{
						throw new IllegalStateException("Each column must have unique id");
					}
				}
			}
		}
	}

	/**
	 * Invoked when client change the column state (e.g. resize or reorder a column).
	 * 
	 * @see #getColumnState()
	 */
	public void onColumnStateChanged()
	{

	}

	SubmitColumnStateBehavior submitColumnStateBehavior = new SubmitColumnStateBehavior();

	/**
	 * Ajax behavior that submits column state to server
	 * 
	 * @author Matej Knopp
	 */
	private class SubmitColumnStateBehavior extends AbstractDefaultAjaxBehavior
	{
		private static final long serialVersionUID = 1L;

		@Override
		protected void respond(AjaxRequestTarget target)
		{
			// get the columnState request parameter (set by javascript)
			String state = getRequest().getRequestParameters()
				.getParameterValue("columnState").toString(null);
			if(!Strings.isEmpty(state)){
				// apply it to current state
				columnState.updateColumnsState(state);

				onColumnStateChanged();
			}
		}
    
    @Override
		protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
		{
			super.updateAjaxAttributes(attributes);

			CharSequence columnStateParameter = "return {'columnState': columnState}";
			attributes.getDynamicExtraParameters().add(columnStateParameter);
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public CharSequence getCallbackScript()
		{
			return getCallbackFunction(CallbackParameter.context("columnState"));
		}
	}

	/**
	 * Manages order, visibility and sizes of columns.
	 */
	private ColumnsState columnState;

	/**
	 * Returns the column state.
	 * 
	 * @see ColumnsState
	 * @return state of columns
	 */
	public ColumnsState getColumnState()
	{
		return columnState;
	}

	/**
	 * Sets a new column state. The state must not be null and must match current set of columns,
	 * i.e. for every column in grid there must be entry in the given state.
	 * 
	 * @see ColumnsState
	 * @param columnState
	 *            new column state
	 */
	public void setColumnState(ColumnsState columnState)
	{
		if (columnState == null)
		{
			throw new IllegalArgumentException("ColumnStateManager may not be null.");
		}
		if (!columnState.matches(columns))
		{
			throw new IllegalArgumentException("ColumnStateManager doesn't match current columns.");
		}
		this.columnState = columnState;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.wicket.Component#onInitialize()
	 */
	@Override
	protected void onInitialize()
	{
		super.onInitialize();

		for (IGridColumn column : columns)
		{
			column.setGrid(this);
		}
	}

	@Override
	protected void onBeforeRender()
	{
		setFlag(FLAG_RENDERING, true);

		super.onBeforeRender();
	}

  //TODO: w/ the OnInitialize -> OnBeforeRender can FLAG_RENDERING be removed?
	@Override
	protected void onAfterRender()
	{
		super.onAfterRender();

		setFlag(FLAG_RENDERING, false);
	}

	private RepeatingView topToolbarContainer;
	private RepeatingView bottomToolbarContainer;
	private RepeatingView headerToolbarContainer;

	/**
	 * Adds toolbar to specified container
	 * 
	 * @param toolbar
	 * @param container
	 */
	private void addToolbar(AbstractToolbar toolbar, RepeatingView container)
	{
    Args.notNull(toolbar, "toolbar");

		// create a container item for the toolbar (required by repeating view)
		WebMarkupContainer item = new WebMarkupContainer(container.newChildId());
		item.setRenderBodyOnly(true);
		item.add(toolbar);

		container.add(item);
	}

	/**
	 * Adds a toolbar to the top section (above the grid header).
	 * 
	 * @see AbstractToolbar
	 * @param toolbar
	 *            toolbar instance
	 */
	public void addTopToolbar(AbstractToolbar toolbar)
	{
		addToolbar(toolbar, topToolbarContainer);
	}

	/**
	 * Adds a toolbar to the bottom section (below the actual data).
	 * 
	 * @see AbstractToolbar
	 * @param toolbar
	 *            toolbar instance
	 */
	public void addBottomToolbar(AbstractToolbar toolbar)
	{
		addToolbar(toolbar, bottomToolbarContainer);
	}

	/**
	 * Ads a toolbar to the header section (below the grid header, above the actual data).
	 * 
	 * @see AbstractToolbar
	 * @param toolbar
	 *            toolbar instance
	 */
	public void addHeaderToolbar(AbstractHeaderToolbar toolbar)
	{
		addToolbar(toolbar, headerToolbarContainer);
	}

	/**
	 * INTERNAL
	 * 

* Id of toolbar item (inside toolbar repeaters). */ static public final String INTERNAL_TOOLBAR_ITEM_ID = "item"; /** * Model for the markup of empty row (first data row that has zero height). The empty row is * needed for maintaining layout of the other rows. * * @author Matej Knopp */ private class EmptyRowModel extends Model { private static final long serialVersionUID = 1L; /** * {@inheritDoc} */ @Override public String getObject() { StringBuilder result = new StringBuilder(); for (int i = 0; i < getActiveColumns().size(); ++i) { result.append(""); } return result.toString(); } } /** * Component that represents the grid header. * * @see ColumnsHeader * @author Matej Knopp */ private class Header extends ColumnsHeader { private static final long serialVersionUID = 1L; private Header(String id) { super(id); } @Override Collection> getActiveColumns() { return AbstractGrid.this.getActiveColumns(); } @Override int getColumnWidth(IGridColumn column) { int width = getColumnState().getColumnWidth(column.getId()); if (width != -1 && column.getSizeUnit() == SizeUnit.PX) { return width; } else { return column.getInitialSize(); } } @Override protected void sortStateChanged(AjaxRequestTarget target) { onSortStateChanged(target); } } /** * Invoked when sort state of this grid has changed (e.g. user clicked a sortable column * header). By default refreshes the grid. * * @param target */ protected void onSortStateChanged(AjaxRequestTarget target) { target.add(this); } /** * Generates the javascript required to initialize the client state for this grid instance. * Called after every grid render. * * @return generated javascript code */ private String getInitializationJavascript() { AppendingStringBuffer sb = new AppendingStringBuffer(128); sb.append("(function() {\n"); // initialize the columns sb.append("var columns = [\n"); Collection> columns = getActiveColumns(); int i = 0; for (IGridColumn column : columns) { ++i; sb.append(" {"); sb.append(" minSize: " + column.getMinSize()); sb.append(", maxSize: " + column.getMaxSize()); sb.append(", id: \"" + column.getId() + "\""); sb.append(", resizable: " + column.isResizable()); sb.append(", reorderable: " + column.isReorderable()); sb.append(" }"); if (i != columns.size()) { sb.append(","); } sb.append("\n"); } sb.append("];\n"); // method that calls the proper listener when column state is changed sb.append("var submitStateCallback = "); sb.append(submitColumnStateBehavior.getCallbackScript()); sb.append("\n"); // initialization sb.append("InMethod.XTableManager.instance.register(\"" + getMarkupId() + "\", columns, submitStateCallback);\n"); sb.append("})();\n"); return sb.toString(); } /** * Returns collection of currently visible columns. * * @return collection of currently visible columns */ public Collection> getActiveColumns() { return getColumnState().getVisibleColumns(columns); } /** * Returns the list of all columns in this grid. * * @return list of columns */ public List> getAllColumns() { return Collections.unmodifiableList(columns); } // contains all columns private final List> columns; private GridSortState sortState = null; /** * Returns the sort state of this grid. * * @see IGridSortState * @see GridSortState * * @return sort state */ public GridSortState getSortState() { if (sortState == null) { sortState = new GridSortState(this); } return sortState; } /** * Constant for the Vista theme (default). */ public static final String THEME_VISTA = "imxt-vista"; private String theme = THEME_VISTA; /** * Sets the grid theme. Grid theme is used as CSS style class for the grid. The theme itself * consist of a proper style definition in stylesheet. For more information on custom theme * creation see the custom theme example. * * @param theme * theme identifier */ public void setTheme(String theme) { this.theme = theme; } /** * Returns the theme identifier * * @return theme identifier * @see #setTheme(String) */ public String getTheme() { return theme; } // set during rendering of whole componen private static int FLAG_RENDERING = FLAG_RESERVED8; /** * {@inheritDoc} */ @Override protected void onComponentTag(ComponentTag tag) { super.onComponentTag(tag); CharSequence klass = tag.getAttribute("class"); if (klass == null) { klass = ""; } if (klass.length() > 0) { klass = klass + " "; } klass = klass + "imxt-grid " + getTheme(); klass = klass + " imxt-selectable"; tag.put("class", klass); if (tag.getName().equals("table")) { tag.setName("div"); } } public static final JavaScriptResourceReference JS_YAHOO = new JavaScriptResourceReference(AbstractGrid.class, "res/yahoo.js"); public static final JavaScriptResourceReference JS_EVENT = new JavaScriptResourceReference(AbstractGrid.class, "res/event.js"); public static final JavaScriptResourceReference JS_DOM = new JavaScriptResourceReference(AbstractGrid.class, "res/dom.js"); public static final JavaScriptResourceReference JS_SCRIPT = new JavaScriptResourceReference(AbstractGrid.class, "res/script.js"); public static final JavaScriptResourceReference JS_SCRIPT_JQ = new JavaScriptResourceReference(AbstractGrid.class, "res/script-jq.js"); public static final PackageResourceReference CSS = new PackageResourceReference(AbstractGrid.class, "res/style.css"); /** * Flag to set/un-set the use of YUI as backing JS library. Its default is false and jquery is * used as backing JS library. */ private boolean useYui = false; /** * {@inheritDoc} */ @Override public void renderHead(IHeaderResponse response) { CoreLibrariesContributor.contributeAjax(getApplication(), response); if(isUseYui()) { response.render(JavaScriptHeaderItem.forReference(JS_YAHOO)); response.render(JavaScriptHeaderItem.forReference(JS_EVENT)); response.render(JavaScriptHeaderItem.forReference(JS_DOM)); response.render(JavaScriptHeaderItem.forReference(JS_SCRIPT)); } else { // jquery is already part of Wicket. So there is nothing more to include. response.render(JavaScriptHeaderItem.forReference(JS_SCRIPT_JQ)); } response.render(CssHeaderItem.forReference(CSS)); } /** * Alters the selection state of item specified by the item model. * * @param itemModel * item model * @param selected * true if the item should be selected, false otherwise. */ public abstract void selectItem(IModel itemModel, boolean selected); /** * Marks all currently displayed items as selected. For {@link DataGrid} this selects all items * on current page, for {@link TreeGrid} this selects all currently visible nodes. */ public abstract void selectAllVisibleItems(); /** * Deselects all items. This method marks all items (not just visible items) as no selected. */ public abstract void resetSelectedItems(); /** * Queries whether the item specified by itemModel is currently selected. * * @param itemModel * item model * @return true if the item is selected, false otherwise */ public abstract boolean isItemSelected(IModel itemModel); /** * Returns the collection of models of all currently selected items. * * @return collection of models of currently selected items */ public abstract Collection> getSelectedItems(); /** * Sets whether user will be able to select more than one item. * * @param value * true if the user will be able to select more than one item at a time, * false otherwise (single selection mode). */ public abstract void setAllowSelectMultiple(boolean value); /** * Returns whether user will be able to select more than one item at a time. * * @return true if multiple items can be selected at a time, false * otherwise. */ public abstract boolean isAllowSelectMultiple(); /** * During an Ajax request this method updates the changed grid rows. *

* The definition of "changed" varies in {@link DataGrid} and {@link TreeGrid}. *

    *
  • In both grids the items for which the selection state changed are considered changed. *
  • In {@link TreeGrid} the changes to {@link TreeModel} itself are being tracked (assuming * the proper listeners are fired) and all rows that need to be updated are also considered * changed. *
  • In {@link DataGrid} the items that need to be updated can be marked by * {@link DataGrid#markItemDirty(IModel)} or {@link DataGrid#markAllItemsDirty()}. The grid * itself doesn't track changes to specific items (apart from the selection state). *
*/ public abstract void update(); /** * Invoked when an item selection state has been changed. * * @param item * item model * @param newValue * true if the item became selected, false otherwise. */ protected void onItemSelectionChanged(IModel item, boolean newValue) { } private String lastClickedColumn = null; public IGridColumn getLastClickedColumn() { for (IGridColumn column : columns) { if (column.getId().equals(lastClickedColumn)) { return column; } } return null; } public void cleanLastClickedColumn() { lastClickedColumn = null; } protected boolean disableRowClickNotifications() { return false; } /** * Called after a grid row has been populated. This method allows adding behaviors to grid rows. * * @param rowComponent */ protected void onRowPopulated(final WebMarkupContainer rowComponent) { if (disableRowClickNotifications()) { return; } rowComponent.add(new AjaxFormSubmitBehavior(getForm(), "click") { private static final long serialVersionUID = 1L; @Override protected void onSubmit(AjaxRequestTarget target) { } @Override protected void onError(AjaxRequestTarget target) { } @SuppressWarnings("unchecked") @Override protected void onEvent(AjaxRequestTarget target) { // preserve the entered values in form components Form form = super.getForm(); form.visitFormComponentsPostOrder(new IVisitor, Void>() { public void component(FormComponent formComponent, IVisit visit) { if (formComponent.isVisibleInHierarchy()) { formComponent.inputChanged(); } } }); String column = getRequest().getRequestParameters() .getParameterValue("column").toString(); lastClickedColumn = column; IModel model = (IModel)rowComponent.getDefaultModel(); IGridColumn lastClickedColumn = getLastClickedColumn(); if (lastClickedColumn != null) { if (onCellClicked(target, model, lastClickedColumn)) { return; } if (lastClickedColumn.cellClicked(model)) { return; } } onRowClicked(target, model); } @Override protected void updateAjaxAttributes(AjaxRequestAttributes attributes) { super.updateAjaxAttributes(attributes); CharSequence columnParameter = "return {'column': Wicket.$(attrs.c).imxtClickedColumn}"; attributes.getDynamicExtraParameters().add(columnParameter); CharSequence precondition = "return InMethod.XTable.canSelectRow(attrs.event);"; AjaxCallListener ajaxCallListener = new AjaxCallListener(); ajaxCallListener.onPrecondition(precondition); attributes.getAjaxCallListeners().add(ajaxCallListener); } @Override public CharSequence getCallbackScript() { return getCallbackFunction(CallbackParameter.context("col")); } }); } protected boolean onCellClicked(AjaxRequestTarget target, IModel rowModel, IGridColumn column) { return false; } protected void onRowClicked(AjaxRequestTarget target, IModel rowModel) { if (isClickRowToSelect()) { boolean selected = isItemSelected(rowModel); if (selected == false || isClickRowToDeselect()) { selectItem(rowModel, !selected); update(); } } } private boolean clickRowToSelect = false; /** * Sets whether a click on grid row should select/deselect the row. * * @see #setClickRowToDeselect(boolean) * @param clickRowToSelect * true if the row selection state should be changed upon a mouse click, * false otherwise. * @return this (useful for method chaining) */ public AbstractGrid setClickRowToSelect(boolean clickRowToSelect) { this.clickRowToSelect = clickRowToSelect; return this; } /** * Returns whether a click on grid row should select/deselect the row. * * @return true if the row click should alter the row selection state, * false otherwise. */ public boolean isClickRowToSelect() { return clickRowToSelect; } private boolean clickRowToDeselect = true; /** * Sets whether a click on selected grid row should deselect it. This only applies when * {@link #setClickRowToSelect(boolean)} is set to true. * * @param clickRowToDeselect * whether clicking a selected row should deselect it */ public void setClickRowToDeselect(boolean clickRowToDeselect) { this.clickRowToDeselect = clickRowToDeselect; } /** * Returns whether clicking a selected row deselects it. * * @return true if clicking a selected row deselects it, false * otherwise. */ public boolean isClickRowToDeselect() { return clickRowToDeselect; } private int contentHeight = 0; private SizeUnit contentHeightSizeUnit; /** * Sets the height of grid content. Content is the part of grid displaying the actual data * (rows), i.e. it doesn't cover the header part and toolbars. When the actual content height is * bigger than specified height, a vertical scrollbar is displayed. * * @param contentHeight * desired height of the content or null is the height should be * determined by the actual height (no scrollbar displayed, defalt value) * @param contentSizeUnit * size unit for the contentHeight */ public void setContentHeight(Integer contentHeight, SizeUnit contentSizeUnit) { if (contentHeight != null) { this.contentHeight = contentHeight; } else { this.contentHeight = 0; } contentHeightSizeUnit = contentSizeUnit; } /** * Returns the content height. * * @return content height or 0 if the content height should be determined by the actual content. * @see #setContentHeight(Integer, SizeUnit) */ public int getContentHeight() { return contentHeight; } /** * Returns the size unit for content height. * * @return size unit */ public SizeUnit getContentHeightSizeUnit() { return contentHeightSizeUnit; } /** * Returns the row in DataTable that contains the child component * * @param child * @return */ public abstract WebMarkupContainer findParentRow(Component child); /** * Returns the row component for specified item. * * @param rowModel * @return */ protected abstract WebMarkupContainer findRowComponent(IModel rowModel); /** * Marks the item from the given model as dirty. Dirty items are updated during Ajax requests * when {@link AbstractGrid#update()} method is called. * * @param model * model used to access the item */ public abstract void markItemDirty(IModel model); private boolean selectToEdit = false; /** * Determines whether selected items should also be editable. This should be set to * false when the grid is both selectable and editable (independently). * * @param selectToEdit * whether selected rows should be editable */ public void setSelectToEdit(boolean selectToEdit) { this.selectToEdit = selectToEdit; } /** * Returns whether selected rows are also editable. * * @return */ public boolean isSelectToEdit() { return selectToEdit; } private final static MetaDataKey EDITING = new MetaDataKey() { private static final long serialVersionUID = 1L; }; /** * Sets the edit mode of the row. If selectToEdit is true, this is same as calling * {@link #selectItem(IModel, boolean)}. * * @see #setSelectToEdit(boolean) * * @param rowModel * row model * @param edit * true if the row should be in editable mode, false * otherwise. */ public void setItemEdit(IModel rowModel, boolean edit) { if (isSelectToEdit()) { selectItem(rowModel, edit); } else { WebMarkupContainer rowComponent = findRowComponent(rowModel); if (rowComponent != null) { boolean editing = Boolean.TRUE.equals(rowComponent.getMetaData(EDITING)); if (editing != edit) { rowComponent.setMetaData(EDITING, edit); markItemDirty(rowModel); } } } } /** * Returns whether the row is in editable mode. * * @param rowModel * @return true if the row is in editable mode, false otherwise. */ public boolean isItemEdited(IModel rowModel) { if (isSelectToEdit()) { return isItemSelected(rowModel); } else { WebMarkupContainer rowComponent = findRowComponent(rowModel); if (rowComponent != null) { return Boolean.TRUE.equals(rowComponent.getMetaData(EDITING)); } else { return false; } } } public boolean isUseYui() { return useYui; } public void setUseYui(boolean useYui) { this.useYui = useYui; } }