Wiki Wiki

Listbox component servers to show list of records in standard usage. Due to huge amount of data, the component sometimes got stuck. The paging is highly recommended to use with the new component because it gets lower amount of data, which are transferred to a client because database returns only requested range of records. Next extension is panel with tools, which offers many options to the user how to manage data and increase efficiency of his work.

Architecture#

The development of the component was inspired by MVC ( Model – View – Controller ) pattern and whole implementation was divided into few parts. This complicated component consists of few modules, where everyone has own MVC implementation, and all the modules are covered by main MVC implementation. General part of component is depended only on ZK framework and only last layer of component architecture including HibernateExtension module is dependent on it.

Future extensions#

The design of the library was developed with stress on implementing new features in future. It should mean that the most of features, which somebody could want to implement, will not to cause large structural changes. The future enhancements should bring only minor modifications in the existing code. Every module has own model and controller which has to be extended plus some connection with component and general controller which have to be written but it should be all. In case of some structural request it should be only minor changes because there ought be the lowest possible coupling.

Usage#

Usage of this component is really simple. The following code is enough to create a completely working component by ZK framework. This code is written into ZUL file.
 <listControl paging="false" apply="${ctl.listboxCtl}" />
    <listbox apply="${ctl.listboxCtl}" selectedItem="@{ctl.selectedEntity}" selectFirstRow="true" >
        <listhead>
            <listheader label="First column label"  sort="db()" defaultSort="asc"/>
            <listheader label="Second column label" sort="db()" />
            <listheader label="Third column label"  sort="db()"/>
        </listhead>

        <listitem id="listitemAkce" self="@{each=row}" >
            <listcell label="@{row.firstColumn}" />
            <listcell label="@{dil.secondColumn}" />
            <listcell label="@{dil.thirdColumn'}" />
        </listitem >
    </listbox>
    <paging apply="${ctl.listboxCtl}" pageSize="20" />

This code defines the simplest listbox with 3 columns, above it is component listcontrol, which provides addtional functions like managers, and below that is paging with page size 20. Controller for these component is defined in window’s controller and is accessible through “ctl” variable. There is also property or setter and getter for name “selectedEntity”. Model is loaded through controller.

Now when we have defined the component we have to define its controller, which provides all of demanded features like direct access to the database. It is defined in the window’s controller. When the controller is declared there has to be implemented method for database access. There is recommended to use our module which is based on GenericDAO and Hibernate framework to provide your DAO management but is not the condition. The easiest way how to set the controller is to use Data Injection or our annotations – in this case @ZkController or @ZkModel ( depends on usage ).

 @ZkController
    private DLListboxController<OurEntity> listboxCtl = new DLListboxCriteriaController<OurEntity>("listboxOurEntity") 
    { 

        @Override
        protected DLResponse loadData(DLSearch search) {
            return service.findOurEntity(search); // service is object of SOA 
        }
    };

This code shows how to define the simple listbox and its controller. There are also many options and configurations, which can be used, but they are described in the part with listbox configuration. ZK framework is a framework which is full of visual mistakes and bugs so there is recommended to define properties with format parameters like width and height – it prevents the visual errors. Some of extending properties are used to help to solve these bugs.

Annotation says that this property should be accessible from ZUL, method load data says how to get model with given filters and sorts. Usually web applications uses SOA so there is called one of services.

Reference#

Basic listbox component#

This component is originated in ZK listbox and it has full backward compatibility. Although some of attributes were overloaded the main purpose was kept. There is a list of new attributes and their sense.
  • Controller ( apply )
    • This is required attribute when user want to use our enhancements and receives the existing instance of listbox controller. Usually this is set through databinding because it makes code more transparent. For example there is used read-only databinding:
    • applyr=“${ctl.listboxCtl}“
  • selectFirstRow
    • This attribute says that there is automatically selected first row when new model is set so there cannot occur the situation that the selected item is null when the model is not empty.
    • This is overwritten by databinding setValue so the user-selected value is kept.
    • This rule is used also onPaging if the selected value is reseted. The reset has to be done manually in the method loadData()
    • The default value is false

DLListheader#

This tag defines column in listbox and usually is used to display some entity's property. This column can be defined through databinding, which makes simple other operations with column as filtering, sorting or exporting. Binding is loaded from label attribute in corresponding Listcell but if the attribute is not filled with binding then for the good functionality has to be defined some supported attributes. Defined binding provides the path to the entity's property and its type.
  • column
    • defines attribute of entity. This definition overwrites the databinding and when the value is set or get then the getter and setter is used if is defined. Otherwise the direct access is used. This column is usually defined when the databinding is not used or Listcell has more complex implementation than its label.
  • ColumnType
    • defines type of entity's property. The definition overwrites the type detected through databinding path. It is used eg. for type conversions in filtering or exporting.
    • This attribute is usually used when databinding is not used or Listcell is more complex
    • There is expected full name of type including package name, eg. java.lang.String
  • Converter
    • converter is class which transforms given data into printable output. For example if the attribute is decimal number then converter can be used to format number of decimal places. Given number is converted to string with precision of two position.
    • Converter is used also in exporting
    • Expected output is String or some other simple type which can be easily shown.
    • Converter can be given through two ways
      • full converter's class name including package name – this class has to implement method “coerceToUi” and in public constructor without any parameter. It this class is found then is created through ClassLoader and method newInstance().
      • Another way is to define converting method in controller and link this method with notation converter=”ctl.myConvertingMethod”. This method has to receive one Object parameter and return standard output.
  • sort
    • this parameter defines the method of default sorting of column. There are received few formats of input
      • auto – it calls default ZK sorting implementation, which sorts records in actual model. This type of sorting can be a little confusing because user probably doesn't see all of data and sorting is proceeded over that selected part of them not over the all of them. This is not recommended style with direct connection into database.
      • auto( column ) - calls default ZK sort implementation on the specified column
      • none – sorting is disabled
      • db() - sorting is executed in the database which is highly recommended because database machines are optimized for this type of operations. The sorting is executed over all of data which is what user expects. The sorting is executed on column defined via binding or attribute.
      • db( column ) - this is similar to the previous type expect the column. There is column defined explicitly with full path from the root entity in this listbox.
  • defaultSort
    • this parameter sets the kind of sorting which is active on page loading. Accepted values are “asc” for ascending, “desc” for descending and “natural” for unsorted column, which is the default option.
  • filter
    • this attribute says if the column is filterable. It affects quick and normal filter. This attribute is not overwritten by anyone.
    • The columns with the specific type and undefined compiler shouldn't be filterable due to user's confusion. These columns are displayed in column-lists so user can define criteria but library doesn't know the way how to work with it so it is ignored and logged. User thinks that his filters are active but it is not truth.
  • filterCompiler
    • Except the primitive types there are allowed also the complex types. With primitive types are understood strings, integers, doubles etc. With complex types are understood entities and other objects. With these types the library cannot work so there has to be defined supporting components or some functions are disabled. The supporting components are understood filterCompiler and filterComponent which allow the library to process input from user and proceed it into database.
    • FilterCompiler says how to compile user input to sql query. If there is used hibernate framework, the queries are Restrictions, if there is used SimpleController then it is evaluation.
    • This attribute can be defined always when the programmer wants to redefine standard behavior or wants to define instructions how to proceed it. When the column is proceeded the definition of specific compiler is detected. If the compiler is not found and type of column is recognized and known then the standard compiler is used. Otherwise the column is ignored and exception is logged.
    • Compiler has to implement FilterCompiler interface and is set through two ways
      • the first is to set an existing instance eg. for databinding filterCompiler=”${ctl.myFilterCompiler}”
      • Another way is to define full class name. This class has to implement public constructor with no parameters
    • Compiler can be created with few ways
      • in the library is implemented AbstractFilterCompiler which contains huge switch for all operators and calls appropriate method to be executed. This class can be extended and methods for the operators can be overwritten.
      • Next option is to extend FilterCriterionCompiler or FilterSimpleCompiler, which are used as default compilers, and overwrite appropriate methods.
      • Last way is to implement FilterCompiler interface, which delegates only one method which handles everything. Accepted parameters are operator, column name and values in this order.
    • In some cases the values are only values of filter parameters but in some cases like SimpleController the zeroth value is the value of object which is being compared. Also the result type depends on the situation. In the general case there is expected some type of compiled filter but if there is SimpleController then the boolean result of evaluation is expected.
  • FilterComponent
    • introduction is same like for FilterCompiler
    • If the column contains the complicated object the library couldn't know what component should be displayed in normal filter. This attribute defines the component type which is offered to user to be able to set right value.
    • The component can be also defined always when the programmer founds out that the default auto-detected component is not according to his needs.
    • The library contains few standard components for standard types. These components can be also used in this or modified ( extending ) implementation.
    • Also absolutely new components can be defined but have to implement interface at least FilterComponent or some of his children.
    • FilterComponent offers a validation method which is evaluated on change of value in component. This method can throw WrongValueException which is caught and error bubble hint is displayed nearby this component.
    • FilterComponent can be set through two ways and in this case, the ways means the difference in the implementation. Due to operators with multiple arity, the library has to be able to create new instance of a component.
      • The first option is to define full class name. This class is instantiated through public constructor without parameters. That is the way of creating new instances.
      • Another option is to set an existing ( prototype ) instance. When this instance is used then its clone is created. Due to it the component has to implement CloneableFilterComponent interface. The clone method can have a simple implementation but it is required. Eg.: filterComponent=“${ctl.myFilterComponent}“
      • There are few ways how to define new FilterComponent
        • the basic way is to implement whole FilterComponent interface but in the most of cases it is not necessary.
        • Other way is to extend AbstractFilterComponent which works with the basic ZK component and offers the general implementation of some methods.
        • Next option is to extend some of standard components and for example overwrite validation method.
        • There is necessary to keep in mind a few notes
          • implementation of method with registering of onChangeEvent is require due to each component emits different event when value is changed.
          • Get method should return actual set value in the component
          • Set method is called by initial data binding and the reaction on this event the value should be set to the component
  • filterGeneralComponent
    • many attributes which requires special component also requires special compiler. Due to this there was defined this parameter which accepts filter compiler and filter component at once. This class has to implement both interfaces. Using this type of class leads to decreasing of used classes. On the other hand Java offers only simple inheritance so programmer cannot use abstract classes from both interfaces although both are pretty usable.
    • This attribute is exclusive with filterComponent and filterCompiler
  • filterOperators
    • each column with detected or defined ordinary type has own list of standard operators. But sometimes it would be better if could be redefined.
    • Undetected types or unknown columns must have defined this list explicitly
    • format of this attribute is simple string with short names of operators delimited by comma.
    • These operators are used in normal filter manager and can be caught in filter compiler
    • Library hasn't supported definition of own operators yet
    • Names of operators are:
      • None – none – this column is not involved in normal filter. It has same effect as parameter filter=”false”
      • Equals - eq
      • Not equals – neq
      • Like – like
      • Not like – nlike
      • Starts with – start
      • Ends with – end
      • Greater than – gt
      • Greater equals – ge
      • Lesser than – lt
      • Lesser equals - le
      • Empty – empty
      • Not Empty – nempty
      • Between - between
  • quickFilter
    • defines if this column participates in the quick filter. Switching this off says that this column cannot be specified in quick filter

Paging#

This component displays navigation bar which shows page number, count of pages and allows user to navigate between pages. State of this navibar is connected with listbox model and on paging change emitts event which asks for new listbox model. This component has no backward compatibility. This new implementation requires listbox controller to provide events and models which are managed.
  • Controller
    • This attribute is required, defines listbox controller which provides models and handles paging events.
  • pageSize
    • There is defined number of rows,which are displayed on listbox page. ZK uses lazy loading so records which aren’t curretnly shown aren’t loaded. These records are loaded on display request, which causes that listbox lookes frozen for one or more seconds.
  • Autohide
    • Positive value ( boolean ) in attribut causes that paging is hidden when total page count is equal to one.
  • Detailed
    • This attibut affects the right side of paging which displays the indexes of rows.
  • countPages
    • Paging gets count of pages using count() function in the select query. Due to this aggregation function this request is executed as special query. Huge tables in the database can cause that this counting query can take long time. To avoid long page loading time there can be disabled this query. Instead of page count there are displayed question marks at first. When user goes to empty or incomplete page the page count number is set to this value. According to displayed data and pages this number is getting more accurate.

Filtering#

Quick Filter#

Quick filter component is panel based on Hbox and provides user menu with columns which are available for quick filter, textbox which serves to input filter key and button find. This small component is built in listbox but can be placed in other location but has to be connected with appropriate listbox using controller. If there is attempt to use quick filter with unknown type but known column there is automatically used equals operator. This is important when programmer defines his own filter compiler.
  • controller
    • this attribute is required because it makes the connection with listbox component.
  • quickFilterAll
    • Default filters offers list of columns and one special key called ALL which says that user wants to filter across all columns. This key can be disabled with this value.
  • quickFilterDefault
    • There is specified default filter value which is used to filter.

Easy Filter#

This type of filter is not an actual component. This represents type of filter which can be included into pages. Using databinding there can be defined components and they can set their values as filter parameters to listbox filter model. Syntax of these special bindings is pretty simple. At first in the window controller has to be called method which publishes easy filter model to ZUL file. This method is named registerEasyFilterVariable(). This method registers filter model to the specific component with desired name. This name is used in databinding to provide the access for filter parameters. Each component is binded on specified operator. Path in the entity which uses dot notation have to be converted to # notation – it means that all dots have to be replaced with #. These chars are replaced back but it could cause problems in databinding.

Examle:

 myListboxController.registerEasyFilterVariable(“windowIdentifier”, “summaryListboxFilter”);
// this method publishes easyfilter model with name “summaryListboxFilter”
// in whole context of component with id “windowIdentifier”

<textbox value=”@{summaryListboxFilter.eq.user#name}” />
// this means that textbox value is binded to easy filter with operator equals on field “user.name”

ListboxController also offers methods which can register listeners on components. These listeners can serve as onFilter or onClear event handlers. Methods are named registerEasyFilterOnFilter and registerEasyFilterOnClear.

Default Filter#

This type of filter servers to define specific parameters which should be always involved for whole listbox. These parameters are set through the method addDefaultFilter called on ListboxController.

Normal Filter#

This is advanced filter offering many options how to configure filter parameters. In the page it is represented by icon which invokes modal window. This window displays list of available columns and user can set values and operators which will be used as filter criteria in this listbox. Normal filter icon is part of DLListControl which is automatically shown in default configuration.

External Filter#

Last option how to filter data is to define criteria in DAO layer. This layer is depended on the specific system and lays out of this library. For this purpose we produced GenericDAO module which offers default generic implementation of DAO objects which are enough in most cases. Also other implementations of DAO have a space to add some other criteria into the list.

WYSIWYG Filter#

When the DLFilter is used instead of the database solution, there is an issue with converters and proper type matching. To provide to the user the deterministic and logical behavior there is a property ensuring the string-based filter matching. All the converters are applied on the values and then the string operator contains is used to determine whether or not the value matches the pattern.

To enable WYSIWYG implementation there are two ways. The global one and the local one, which can override the global one when both are defined. By default, the wysiwyg is not used. There is a code snippet for global definition:

 <library-property>
     <name>zk-dl.filter.wysiwyg</name>
     <value>true</value>
 </library-property>

and the attribute which is defined on the listcontrol component:

 <listControl apply="${ctl.listController}" wysiwyg="true" />
This feature is available since ZKDLComponents version 1.3.10

Managers#

View manager#

Listbox has defined list of columns. Some of them are visible and the others are hidden. User can redefine the propeties which specify the visibility and order. The dialog windows displays two lists showing list of visible and list of hidden columns. These lists supports drag and drop to modify their order and belonging to.

MS Excel export#

Export is based on jxl library which has direct support of MS Excel. This library offers wide api to create Excel files with cells and their formats. Export takes data from databinding including converters and tries to convert data into some supported datatype. There is expected that datatype is common or has its own converter to it. Datatype recognition stems from databinding entity but if the specified property of entity is uncommon or databinding is missing then has to be used attribute columnType. This type is used to resolve format of cell. If the databinding is not used then has to be defined also attribute column to specify the property of entity in the model which is acquired via method loadData().

Sort manager#

In listbox model can be defined apart from filter criteria also sorting parameters due to database usage for acquiring the model. These parameters say how data should be sorted. Due to the database usage this operation is pretty quick so the component can offer user to specify more than one column. The list of columns, priorities and types of sort is shown in this modal window and then the inserted values are added to the list of parameters which is sent to the method loadData();

Controller#

DLListcontrol#

This component covers the configuration of listbox additions. This component includes configuration for paging, quick filter and manager. This component should be included in listbox configuration and according its configuration there are generated appropriate components.
  • autohide – paging configuration property
  • countPages – paging configuration property
  • pageSize – paging configuration property
  • paging – expects boolean value which says if the paging should be created in this place or not
  • manager – expects boolean value which says if the manager ( which contains all of listbox additions like sortManager and filterManager ) should be created in this place or not
  • qFilter – expects boolean value which says if the quick filter should be created in this place or not
  • quickFilterAll – quickFilter property
  • quickFilterDefault – quickFilter property

Other examples:#

Advanced configured listbox:#

 <listControl paging="false" apply="${ctl.listboxCtl}">
        <button id="addItem"  image="/ico/add.png"  mold="os" tooltiptext="Add"  disabled="${uzivateleServiceImpl.spectator}" />
        <button id="editItem" image="/ico/edit.png" mold="os" tooltiptext="Edit" disabled="${uzivateleServiceImpl.spectator}" />
    </listControl>
    <listbox apply="${ctl.listboxCtl}" selectedItem="@{ctl.selectedEntity}" selectFirstRow="true" >
        <listhead>
            <listheader label="First column label"  sort="db(firstProperty.otherProperty)" defaultSort="asc"/>
            <listheader label="Second column label" sort="db()" column="booleanValue"/>
            <listheader label="Third column label"  sort="db()"/>
            <listheader label="Fourth column label" sort="db()" filterOperators="eq,neq"
                    filterComponent="cz.datalite.compilers.EnumCompiler" 
                    filterCompiler="cz.datalite.zk.components.list.filter.components.EnumFilterComponent"/>
        </listhead>

        <listitem id="listitemAkce" self="@{each=row}" >
            <listcell label="@{row.firstColumn}" />
            <listcell>
                <checkbox value="@{row.booleanValue}"  readonly="true"/>
            </listcell>
            <listcell label="@{row.booleanProperty, converter='cz.datalite.helpers.converters.SomeConverter'}" />
            <listcell label="@{row.enumProperty}"/>
        </listitem >
    </listbox>
    <paging apply="${ctl.listboxCtl}" pageSize="20" autohide="false"/>
 @ZkController
    private DLListboxController<OurEntity> listboxCtl = new DLListboxCriteriaController< OurEntity >("listboxOurEntity") {
        
        { 
          // unary operator, filter which is always involved into each search requests
          addDefaultFilter( "someProperty", DLFilterOperator.EQUAL, "some value",null); 
        }

        @Override
        protected DLResponse loadData(DLSearch search) {
            search.addFilterCriterion(Restrictions.sql("own sql where clausule"));
        }
            return service.findOurEntity(search);
        }
    };

Definition of filter compiler which handles enumeration types.

 /**
* Compiler for concrete enum, nowdays there is
* not universal implementation. There is enum
* called OurEnum and method getDescription
* returns label which is shown to user.
*
* Possible universal solutions is based on
* toString() method but there is problem how to
* define enum which values should be seeked through.
* 
*/
public class EnumCompiler extends FilterCriterionCompiler {

    @Override
    protected Criterion compileOperatorEqual(final String key, final Object... values) {
        final Object value = values[0];
        if (value instanceof String) { // input from Quick Filter
            Disjunction disj = Restrictions.disjunction();
            final String val = (String) value;
            for (OurEnum enumeration : OurEnum.values()) {
                // looking up in descriptions
                if (enumeration.getDescription().toUpperCase().contains(val.toUpperCase())) {
                    disj.add(Restrictions.eq(key, enumeration));
                }
            }
            return disj.add(Restrictions.sqlRestriction("1=0"));
        } else if ((value instanceof OurEnum)) // input from normal filter EnumFilterComponent
            return Restrictions.eq(key, value);
        } else {
            return Restrictions.sqlRestriction("1=0");
        }

    }

    @Override
    protected Criterion compileOperatorNotEqual(final String key, final Object... values) {
        // there is input only from normal filter
        final Object value = values[0];
        return Restrictions.ne(key, value);
    }
}

Usage of FilterComponent with combobox

  • in ZUL is set instance filterComponent=”{ctl.comboFilterComponent}”
  • in controller is define this component based on EnumFilterComponent
 @ZkController
FilterComponent comboFilterComponent = new EnumFilterComponent(
                service.findAllMyEntities() ,
                ”nameOfSomePropertyToBeShown”
             ); // there is also possible instead of property name in dot notation to use the ComboitemRenderer
// method findAllMyEntities() returns some list of object in database which should be used
// as combobox model. Property name in dot notation says which property should be displayed. 

Definition of own FilterComponent but probably it is rarely necessary. This example is based on library implementation of components

 /**
* Standard implementation of the filter component for checkboxes. There are
* no validation additions, each of restrictions comes from the component.
*/
public class BooleanFilterComponent implements FilterComponent {

    protected final Checkbox component;

    public BooleanFilterComponent() {
        component = new Checkbox();
    }

    public Component getComponent() {
        return component;
    }

    public Object getValue() {
        return component.isChecked();
    }

    public void setValue( final Object value ) {
        component.setChecked( value == null ? false : ( Boolean ) value );
    }

    public void addOnChangeEventListener( final EventListener listener ) {
        component.addEventListener( Events.ON_CHECK, listener );
        Events.postEvent( new Event( Events.ON_CHECK, component ) );
    }

    public void validate() throws WrongValueException {
        // no validation required
    }
}
0 Přílohy
13163 Zobrazení
Průměr (0 Hlasů)
Komentáře