com.panemu.tiwulfx.control.LookupFieldController.java Source code

Java tutorial

Introduction

Here is the source code for com.panemu.tiwulfx.control.LookupFieldController.java

Source

/*
 * License GNU LGPL
 * Copyright (C) 2012 Amrullah <amrullah@panemu.com>.
 */
package com.panemu.tiwulfx.control;

import com.panemu.tiwulfx.common.TableCriteria;
import com.panemu.tiwulfx.common.TableData;
import com.panemu.tiwulfx.common.TiwulFXUtil;
import com.panemu.tiwulfx.table.BaseColumn;
import com.panemu.tiwulfx.table.CheckBoxColumn;
import com.panemu.tiwulfx.table.LocalDateColumn;
import com.panemu.tiwulfx.table.NumberColumn;
import com.panemu.tiwulfx.table.TableControl;
import com.panemu.tiwulfx.table.TableControl.Component;
import com.panemu.tiwulfx.table.TableController;
import com.panemu.tiwulfx.table.TextColumn;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.SortType;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.Image;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
import org.apache.commons.beanutils.PropertyUtils;

/**
 * Class that serves data loading for LookupField.
 *
 * @author Amrullah <amrullah@panemu.com>
 */
public abstract class LookupFieldController<T> {

    private LookupWindow lookupWindow;
    private Stage dialogStage;
    private Class<T> recordClass;

    /**
     *
     * @param recordClass The class of record/object/POJO that will be displayed
     * in table's row
     */
    public LookupFieldController(Class<T> recordClass) {
        this.recordClass = recordClass;
    }

    public abstract String[] getColumns();

    /**
     * This method is published to serve data displayed on Lookup's suggestion
     * list. Eventually it will call
     * {@link #loadData(int, java.util.List, java.util.List, java.util.List, int)}
     *
     * @param propertyName
     * @param key
     * @return
     */
    public List<T> loadDataForPopup(String propertyName, String key) {
        return loadDataForPopup(propertyName, key, TableCriteria.Operator.ilike_anywhere);
    }

    /**
     * This method is published to serve data displayed on Lookup's suggestion
     * list. Eventually it will call
     * {@link #loadData(int, java.util.List, java.util.List, java.util.List, int)}
     *
     * @param propertyName
     * @param key
     * @param operator
     * @return
     */
    public List<T> loadDataForPopup(String propertyName, String key, TableCriteria.Operator operator) {
        List<TableCriteria> lstCriteria = new ArrayList<>();
        if (key != null && !key.isEmpty()) {
            lstCriteria.add(new TableCriteria(propertyName, operator, key));
        }
        TableData data = loadData(0, lstCriteria, Arrays.asList(propertyName), Arrays.asList(SortType.ASCENDING),
                TiwulFXUtil.DEFAULT_LOOKUP_SUGGESTION_ITEMS);
        return (List<T>) data.getRows();
    }

    /**
     *
     * @return
     */
    protected String getWindowTitle() {
        return TiwulFXUtil.getLiteral("lookup.title");
    }

    public T show(Window stage, T initialValue, String propertyName) {
        return show(stage, initialValue, propertyName, null);
    }

    /**
     * Show lookup dialog.
     *
     * @param stage parent
     * @param initialValue this value will be returned if user clik the close
     * button instead of double clicking a row or click Select button
     * @param propertyName propertyName corresponds to searchCriteria
     * @param searchCriteria searchCriteria (nullable)
     * @return selected object or the initialValue
     */
    public T show(final Window stage, T initialValue, String propertyName, String searchCriteria) {
        if (dialogStage == null) {
            PropertyDescriptor[] props = PropertyUtils.getPropertyDescriptors(recordClass);
            lookupWindow = new LookupWindow();
            for (String clm : getColumns()) {
                for (PropertyDescriptor prop : props) {
                    if (prop.getName().equals(clm)) {
                        Class type = prop.getPropertyType();
                        if (type.equals(Boolean.class)) {
                            lookupWindow.table.addColumn(new CheckBoxColumn<T>(clm));
                        } else if (type.equals(String.class)) {
                            lookupWindow.table.addColumn(new TextColumn<T>(clm));
                        } else if (type.equals(Date.class)) {
                            lookupWindow.table.addColumn(new LocalDateColumn<T>(clm));
                        } else if (Number.class.isAssignableFrom(type)) {

                            if (Long.class.isAssignableFrom(type)) {
                                lookupWindow.table.addColumn(new NumberColumn<T, Long>(clm, type));
                            } else {
                                lookupWindow.table.addColumn(new NumberColumn<T, Double>(clm, type));
                            }
                        } else {
                            TableColumn column = new TableColumn();
                            column.setCellValueFactory(new PropertyValueFactory(clm));
                            lookupWindow.table.addColumn(column);
                        }
                        break;
                    }
                }

            }
            dialogStage = new Stage();
            if (stage instanceof Stage) {
                dialogStage.initOwner(stage);
                dialogStage.initModality(Modality.WINDOW_MODAL);
            } else {
                dialogStage.initOwner(null);
                dialogStage.initModality(Modality.APPLICATION_MODAL);
            }
            dialogStage.initStyle(StageStyle.UTILITY);
            dialogStage.setResizable(true);
            dialogStage.setScene(new Scene(lookupWindow));
            dialogStage.getIcons().add(new Image(
                    LookupFieldController.class.getResourceAsStream("/com/panemu/tiwulfx/res/image/lookup.png")));
            dialogStage.setTitle(getWindowTitle());
            dialogStage.getScene().getStylesheets()
                    .add(getClass().getResource("/com/panemu/tiwulfx/res/tiwulfx.css").toExternalForm());
            initCallback(lookupWindow, lookupWindow.table);
        }

        for (TableColumn column : lookupWindow.table.getTableView().getColumns()) {
            if (column instanceof BaseColumn && ((BaseColumn) column).getPropertyName().equals(propertyName)) {
                if (searchCriteria != null && !searchCriteria.isEmpty()) {
                    TableCriteria tc = new TableCriteria(propertyName, TableCriteria.Operator.ilike_anywhere,
                            searchCriteria);
                    ((BaseColumn) column).setTableCriteria(tc);
                } else {
                    ((BaseColumn) column).setTableCriteria(null);
                }

                break;
            }
        }
        selectedValue = initialValue;
        beforeShowCallback(lookupWindow.table);
        lookupWindow.table.reloadFirstPage();

        if (stage != null) {
            /**
             * Since we support multiple monitors, ensure that the stage is
             * located in the center of parent stage. But we don't know the
             * dimension of the stage for the calculation, so we defer the
             * relocation after the stage is actually displayed.
             */
            Runnable runnable = new Runnable() {
                public void run() {
                    dialogStage.setX(stage.getX() + stage.getWidth() / 2 - dialogStage.getWidth() / 2);
                    dialogStage.setY(stage.getY() + stage.getHeight() / 2 - dialogStage.getHeight() / 2);

                    //set the opacity back to fully opaque
                    dialogStage.setOpacity(1);
                }
            };

            Platform.runLater(runnable);

            //set the opacity to 0 to minimize flicker effect
            dialogStage.setOpacity(0);
        }

        dialogStage.showAndWait();
        return selectedValue;
    }

    /**
     * Override this method to get reference on Lookup container and
     * TableControl object. This is useful to set preferred size of lookup
     * window and set particular column's width. This callback is executed after
     * Lookup Stage along with TableControl are ready to be shown. It is only
     * executed one time. The next lookup dialog show will not be called.
     *
     * @param container
     * @param table
     * @see #beforeShowCallback(com.panemu.tiwulfx.table.TableControl)
     */
    protected void initCallback(VBox container, TableControl<T> table) {
    }

    /**
     * Call back that is called every time the lookup dialog is about to be
     * shown.
     *
     * @param table
     * @see #initCallback(javafx.scene.layout.VBox,
     * com.panemu.tiwulfx.table.TableControl)
     */
    protected void beforeShowCallback(TableControl<T> table) {

    }

    private T selectedValue;

    private void select() {
        selectedValue = lookupWindow.table.getSelectedItem();
        close();

    }

    private void close() {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                dialogStage.hide();
            }
        });
    }

    protected abstract TableData loadData(int startIndex, List<TableCriteria> filteredColumns,
            List<String> sortedColumns, List<SortType> sortingTypes, int maxResult);

    private class LookupTableController extends TableController<T> {

        @Override
        public TableData loadData(int startIndex, List<TableCriteria> filteredColumns, List<String> sortedColumns,
                List<SortType> sortingTypes, int maxResult) {
            return LookupFieldController.this.loadData(startIndex, filteredColumns, sortedColumns, sortingTypes,
                    maxResult);
        }

        @Override
        public void doubleClick(T record) {
            select();
        }
    }

    private class LookupWindow extends VBox {

        TableControl<T> table = new TableControl<>();
        private Button button = new Button(TiwulFXUtil.getLiteral("lookup.select"));

        public LookupWindow() {
            addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {

                @Override
                public void handle(KeyEvent event) {
                    if (event.getCode() == KeyCode.ESCAPE) {
                        close();
                    }
                }
            });
            HBox pnlButton = new HBox();
            pnlButton.setAlignment(Pos.CENTER);
            pnlButton.setPadding(new Insets(10));
            pnlButton.getChildren().add(button);

            getChildren().addAll(table, pnlButton);
            table.setController(new LookupTableController());
            table.setVisibleComponents(false, Component.BUTTON_DELETE, Component.BUTTON_EDIT,
                    Component.BUTTON_EXPORT, Component.BUTTON_INSERT, Component.BUTTON_SAVE);
            button.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent t) {
                    select();
                }
            });
        }
    }
}