/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * 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 Lesser General Public License for more details. * * Copyright (c) 2002-2017 Hitachi Vantara.. All rights reserved. */ package org.pentaho.commons.metadata.mqleditor.editor.controllers; import java.util.ArrayList; import java.util.List; import org.pentaho.commons.metadata.mqleditor.beans.Query; import org.pentaho.commons.metadata.mqleditor.editor.MQLEditorService; import org.pentaho.commons.metadata.mqleditor.editor.MqlDialogListener; import org.pentaho.commons.metadata.mqleditor.editor.models.UIColumn; import org.pentaho.commons.metadata.mqleditor.editor.models.UIColumns; import org.pentaho.commons.metadata.mqleditor.editor.models.UIDomain; import org.pentaho.commons.metadata.mqleditor.editor.models.UIModel; import org.pentaho.commons.metadata.mqleditor.editor.models.Workspace; import org.pentaho.ui.xul.XulServiceCallback; import org.pentaho.ui.xul.binding.Binding; import org.pentaho.ui.xul.binding.BindingConvertor; import org.pentaho.ui.xul.binding.BindingFactory; import org.pentaho.ui.xul.components.XulButton; import org.pentaho.ui.xul.components.XulLabel; import org.pentaho.ui.xul.components.XulMenuList; import org.pentaho.ui.xul.components.XulMessageBox; import org.pentaho.ui.xul.components.XulTextbox; import org.pentaho.ui.xul.containers.XulDialog; import org.pentaho.ui.xul.containers.XulTree; import org.pentaho.ui.xul.impl.AbstractXulEventHandler; import org.pentaho.ui.xul.stereotype.Bindable; /** * * This is the main XulEventHandler for the dialog. It sets up the main bindings for the user interface and responds to * some of the main UI events such as closing and accepting the dialog. * */ public class MainController extends AbstractXulEventHandler { public static final int CANCELLED = 0; public static final int OK = 1; private int lastClicked = CANCELLED; private static XulDialog errorDialog; private XulMenuList modelList; private XulMenuList domainList; private XulTree categoryTree; private XulButton acceptButton; private Workspace workspace; private XulTree fieldTable; private XulTree conditionsTable; private XulTree ordersTable; private XulTextbox limit; private XulDialog dialog; private MQLEditorService service; private List<MqlDialogListener> listeners = new ArrayList<MqlDialogListener>(); private Query savedQuery; BindingFactory bf; public MainController() { } public boolean getOkClicked() { return lastClicked == OK; } public void setSavedQuery( Query savedQuery ) { this.savedQuery = savedQuery; if ( savedQuery == null ) { this.clearWorkspace(); } if ( savedQuery != null ) { workspace.wrap( savedQuery ); } } @Bindable public void init() { createBindings(); } public void showDialog() { dialog.show(); conditionsTable.update(); } public void clearWorkspace() { workspace.clear(); } private void createBindings() { modelList = (XulMenuList) document.getElementById( "modelList" ); domainList = (XulMenuList) document.getElementById( "domainList" ); categoryTree = (XulTree) document.getElementById( "categoryTree" ); conditionsTable = (XulTree) document.getElementById( "conditionsTree" ); ordersTable = (XulTree) document.getElementById( "orderTable" ); fieldTable = (XulTree) document.getElementById( "selectedColumnTree" ); dialog = (XulDialog) document.getElementById( "mqlEditorDialog" ); limit = (XulTextbox) document.getElementById( "limit" ); acceptButton = (XulButton) document.getElementById( "mqlEditorDialog_accept" ); errorDialog = (XulDialog) document.getElementById( "errorDialog" ); // bind the selections empty status to the ok button (i.e. if no selections, disable OK button) bf.setBindingType( Binding.Type.ONE_WAY ); final Binding acceptButtonBinding = bf.createBinding( workspace, "selections", acceptButton, "!disabled", new BindingConvertor<List<UIColumns>, Boolean>() { @Override public Boolean sourceToTarget( List<UIColumns> value ) { return value != null && !value.isEmpty(); } @Override public List<UIColumns> targetToSource( Boolean value ) { return null; } } ); // Bind the domain list to the domain menulist drop-down. bf.setBindingType( Binding.Type.ONE_WAY ); final Binding domainBinding = bf.createBinding( this.workspace, "domains", domainList, "elements" ); // Bind the selected index from the domain drop-down to the selectedDomain in the workspace bf.setBindingType( Binding.Type.BI_DIRECTIONAL ); bf.createBinding( domainList, "selectedIndex", workspace, "selectedDomain", new BindingConvertor<Integer, UIDomain>() { @Override public UIDomain sourceToTarget( Integer value ) { if ( value < 0 || value > workspace.getDomains().size() ) { return null; } return workspace.getDomains().get( value ); } @Override public Integer targetToSource( UIDomain value ) { return workspace.getDomains().indexOf( value ); } } ); // Bind the selectedDomain to the list of models menulist drop-down bf.setBindingType( Binding.Type.ONE_WAY ); Binding domainToList = bf.createBinding( this.workspace, "selectedDomain", modelList, "elements", new BindingConvertor<UIDomain, List<UIModel>>() { @Override public List<UIModel> sourceToTarget( UIDomain value ) { return value.getModels(); } @Override public UIDomain targetToSource( List<UIModel> value ) { return null; // not used } } ); // Bind the selected index of the model dro-down the the selectedModel in the workspace bf.setBindingType( Binding.Type.BI_DIRECTIONAL ); Binding modelToList = bf.createBinding( workspace, "selectedModel", modelList, "selectedIndex", new BindingConvertor<UIModel, Integer>() { @Override public Integer sourceToTarget( UIModel value ) { return workspace.getSelectedDomain().getModels().indexOf( value ); } @Override public UIModel targetToSource( Integer value ) { if ( value < 0 ) { return null; } return workspace.getSelectedDomain().getModels().get( value ); } } ); // Bind the available categories from the selected model to the category/column tree. bf.setBindingType( Binding.Type.ONE_WAY ); bf.createBinding( workspace, "categories", categoryTree, "elements" ); // Bind the selected column from the tree to the workspace bf.createBinding( categoryTree, "absoluteSelectedRows", workspace, "selectedColumns", new BindingConvertor<int[], List<UIColumn>>() { @Override public List<UIColumn> sourceToTarget( int[] array ) { if ( array.length == 0 ) { return null; } int value = array[0]; if ( value < 0 ) { return null; } return workspace.getColumnsByPos( array ); } @Override public int[] targetToSource( List<UIColumn> value ) { int[] positions = new int[value.size()]; int i = 0; for ( UIColumn col : value ) { positions[i++] = workspace.getSelectedCategory().getChildren().indexOf( col ); } return positions; } } ); // Bind the selected columns, conditions and orders to their respective tables bf.createBinding( workspace, "selections", fieldTable, "elements" ); //$NON-NLS-1$ //$NON-NLS-2$ bf.createBinding( workspace, "conditions", conditionsTable, "elements" ); //$NON-NLS-1$ //$NON-NLS-2$ bf.createBinding( workspace, "orders", ordersTable, "elements" ); //$NON-NLS-1$ //$NON-NLS-2$ bf.setBindingType( Binding.Type.BI_DIRECTIONAL ); bf.createBinding( workspace, "limit", limit, "value", new BindingConvertor<Integer, String>() { @Override public String sourceToTarget( Integer value ) { if ( value > -1 ) { return value.toString(); } else { return ""; } } @Override public Integer targetToSource( String value ) { try { if ( value.isEmpty() ) { return -1; } Integer returnInteger = Integer.parseInt( value ); return returnInteger; } catch ( NumberFormatException nfe ) { return workspace.getLimit(); } } } ); try { // Fires the population of the model listbox. This cascades down to the categories and columns. In essence, this // call initializes the entire UI. domainBinding.fireSourceChanged(); } catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); } } @Bindable public void moveSelectionToFields() { List<UIColumn> cols = workspace.getSelectedColumns(); for ( UIColumn col : cols ) { workspace.addColumn( (UIColumn) col.clone() ); } } @Bindable public void moveSelectionToConditions() { List<UIColumn> cols = workspace.getSelectedColumns(); for ( UIColumn col : cols ) { workspace.addCondition( col ); } } @Bindable public void moveSelectionToOrders() { List<UIColumn> cols = workspace.getSelectedColumns(); for ( UIColumn col : cols ) { if ( workspace.getOrders().contains( col ) == false ) { workspace.addOrder( col ); } } } public void setBindingFactory( BindingFactory bf ) { this.bf = bf; } public void setWorkspace( Workspace workspace ) { this.workspace = workspace; } public String getName() { return "mainController"; } @Bindable public void closeDialog() { lastClicked = CANCELLED; this.dialog.hide(); // listeners may remove themselves, old-style iteration for ( int i = 0; i < listeners.size(); i++ ) { listeners.get( i ).onDialogCancel(); } } @Bindable public void saveQuery() { lastClicked = OK; service.saveQuery( workspace.getMqlQuery(), new XulServiceCallback<String>() { public void error( String message, Throwable error ) { System.out.println( message ); error.printStackTrace(); } public void success( String retVal ) { try { XulMessageBox box = (XulMessageBox) document.createElement( "messagebox" ); box.setTitle( "Mql Query" ); retVal = retVal.replace( "><", ">\n<" ); box.setMessage( retVal ); // box.open(); } catch ( Exception e ) { // ignore } workspace.setMqlStr( retVal ); dialog.hide(); for ( MqlDialogListener listener : listeners ) { listener.onDialogAccept( workspace.getMqlQuery() ); } System.out.println( retVal ); } } ); // // service.serializeModel(workspace.getMqlQuery(), // new XulServiceCallback<String>(){ // // public void error(String message, Throwable error) { // System.out.println(message); // error.printStackTrace(); // } // // public void success(String retVal) { // // System.out.println(retVal); // // dialog.hide(); // // } // // } // ); } public MQLEditorService getService() { return service; } public void setService( MQLEditorService service ) { this.service = service; } public void addMqlDialogListener( MqlDialogListener listener ) { if ( listeners.contains( listener ) == false ) { listeners.add( listener ); } } public void removeMqlDialogListener( MqlDialogListener listener ) { if ( listeners.contains( listener ) ) { listeners.remove( listener ); } } @Bindable public static void showErrorDialog( String message ) { if ( errorDialog == null ) { throw new IllegalStateException( "Error dialog has not been loaded yet" ); } else { XulLabel msg = (XulLabel) errorDialog.getElementById( "errorLabel" ); msg.setValue( message ); errorDialog.show(); } } @Bindable public static void closeErrorDialog( String message ) { if ( errorDialog == null ) { throw new IllegalStateException( "Error dialog has not been loaded yet" ); } else { errorDialog.hide(); } } }