/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2013 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ package org.pentaho.di.ui.imp; import java.io.FileWriter; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.ResourceBundle; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.TableEditor; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Dialog; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.ToolBar; import org.pentaho.di.core.Const; import org.pentaho.di.core.KettleEnvironment; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.logging.LogChannel; import org.pentaho.di.core.plugins.ImportRulePluginType; import org.pentaho.di.core.plugins.PluginInterface; import org.pentaho.di.core.plugins.PluginRegistry; import org.pentaho.di.core.xml.XMLHandler; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.imp.ImportRules; import org.pentaho.di.imp.rule.ImportRuleInterface; import org.pentaho.di.ui.core.PropsUI; import org.pentaho.di.ui.core.dialog.EnterSelectionDialog; import org.pentaho.di.ui.core.dialog.ErrorDialog; import org.pentaho.di.ui.core.gui.GUIResource; import org.pentaho.di.ui.imp.rule.ImportRuleCompositeInterface; import org.pentaho.di.ui.spoon.Spoon; import org.pentaho.di.ui.spoon.XulSpoonResourceBundle; import org.pentaho.di.ui.spoon.XulSpoonSettingsManager; import org.pentaho.di.ui.trans.step.BaseStepDialog; import org.pentaho.di.ui.xul.KettleXulLoader; import org.pentaho.ui.xul.XulDomContainer; import org.pentaho.ui.xul.XulLoader; import org.pentaho.ui.xul.containers.XulToolbar; import org.pentaho.ui.xul.impl.XulEventHandler; public class ImportRulesDialog extends Dialog implements XulEventHandler { private static Class<?> PKG = ImportRulesDialog.class; // for i18n private static final String XUL_FILE_TOOLBAR = "ui/import-rules-toolbar.xul"; private Shell parentShell; private Display display; private Shell shell; private PropsUI props; private XulToolbar toolbar; private boolean ok; private ImportRules importRules; private Button wOK, wExport, wImport, wCancel; private Table table; private List<ImportRuleCompositeInterface> compositesList; private ImportRules originalRules; public ImportRulesDialog( Shell parentShell, ImportRules importRules ) { super( parentShell ); this.parentShell = parentShell; this.originalRules = importRules; this.importRules = importRules.clone(); this.props = PropsUI.getInstance(); this.display = parentShell.getDisplay(); } public boolean open() { shell = new Shell( parentShell, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX | SWT.MIN | SWT.APPLICATION_MODAL ); shell.setImage( GUIResource.getInstance().getImageLogoSmall() ); FormLayout formLayout = new FormLayout(); formLayout.marginWidth = Const.FORM_MARGIN; formLayout.marginHeight = Const.FORM_MARGIN; shell.setLayout( formLayout ); shell.setText( BaseMessages.getString( PKG, "ImportRulesDialog.Shell.Title" ) ); // Add the buttons at the very bottom // wOK = new Button( shell, SWT.PUSH ); wOK.setText( BaseMessages.getString( "System.Button.OK" ) ); wOK.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { ok(); } } ); wImport = new Button( shell, SWT.PUSH ); wImport.setText( BaseMessages.getString( PKG, "ImportRulesDialog.Button.Import" ) ); wImport.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { importRules(); } } ); wExport = new Button( shell, SWT.PUSH ); wExport.setText( BaseMessages.getString( PKG, "ImportRulesDialog.Button.Export" ) ); wExport.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { exportRules(); } } ); wCancel = new Button( shell, SWT.PUSH ); wCancel.setText( BaseMessages.getString( "System.Button.Cancel" ) ); wCancel.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { cancel(); } } ); BaseStepDialog.positionBottomButtons( shell, new Button[] { wOK, wImport, wExport, wCancel, }, Const.MARGIN, null ); // Put a toolbar at the very top... // addToolBar(); Control toolbarControl = (Control) toolbar.getManagedObject(); props.setLook( toolbarControl ); toolbarControl.setLayoutData( new FormData() ); FormData fdToolbar = new FormData(); fdToolbar.left = new FormAttachment( 0, 0 ); // First one in the left top corner fdToolbar.top = new FormAttachment( 0, 0 ); fdToolbar.right = new FormAttachment( 100, 0 ); toolbarControl.setLayoutData( fdToolbar ); toolbarControl.setParent( shell ); table = new Table( shell, SWT.FULL_SELECTION | SWT.CHECK | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI ); props.setLook( table ); table.setHeaderVisible( true ); // Enabled? column // TableColumn enabledColumn = new TableColumn( table, SWT.NONE ); enabledColumn.setText( "On?" ); enabledColumn.setWidth( 50 ); // Rule description column // TableColumn descriptionColumn = new TableColumn( table, SWT.NONE ); descriptionColumn.setText( "Rule description" ); descriptionColumn.setWidth( 400 ); // Rule description column // TableColumn compositeColumn = new TableColumn( table, SWT.NONE ); compositeColumn.setText( "Settings" ); compositeColumn.setWidth( 500 ); FormData fdTable = new FormData(); fdTable.top = new FormAttachment( toolbarControl, Const.MARGIN ); fdTable.left = new FormAttachment( 0, 0 ); fdTable.right = new FormAttachment( 100, 0 ); fdTable.bottom = new FormAttachment( wOK, -Const.MARGIN * 2 ); table.setLayoutData( fdTable ); getCompositesData(); table.layout( true, true ); BaseStepDialog.setSize( shell ); shell.open(); while ( !shell.isDisposed() ) { if ( !display.readAndDispatch() ) { display.sleep(); } } return ok; } private void addToolBar() { try { XulLoader loader = new KettleXulLoader(); loader.setSettingsManager( XulSpoonSettingsManager.getInstance() ); ResourceBundle bundle = new XulSpoonResourceBundle( Spoon.class ); XulDomContainer xulDomContainer = loader.loadXul( XUL_FILE_TOOLBAR, bundle ); xulDomContainer.addEventHandler( this ); toolbar = (XulToolbar) xulDomContainer.getDocumentRoot().getElementById( "import-rules-toolbar" ); ToolBar swtToolbar = (ToolBar) toolbar.getManagedObject(); swtToolbar.layout( true, true ); } catch ( Throwable t ) { LogChannel.GENERAL.logError( Const.getStackTracker( t ) ); new ErrorDialog( shell, BaseMessages.getString( PKG, "ImportRulesDialog.Exception.ErrorReadingXULFile.Title" ), BaseMessages.getString( PKG, "ImportRulesDialog.Exception.ErrorReadingXULFile.Message", XUL_FILE_TOOLBAR ), new Exception( t ) ); } } public void addRule() { PluginRegistry registry = PluginRegistry.getInstance(); List<PluginInterface> plugins = registry.getPlugins( ImportRulePluginType.class ); // Loop over the rules in the list and get rid of the ones that are unique in the plugins list. // for ( ImportRuleInterface rule : importRules.getRules() ) { if ( rule.isUnique() ) { int removeIndex = -1; for ( int i = 0; i < plugins.size(); i++ ) { PluginInterface plugin = plugins.get( i ); if ( Const.indexOfString( rule.getId(), plugin.getIds() ) >= 0 ) { removeIndex = i; break; } } if ( removeIndex >= 0 ) { plugins.remove( removeIndex ); } } } // Those that are left can be presented to the user. // if ( plugins.size() > 0 ) { String[] names = new String[plugins.size()]; for ( int i = 0; i < plugins.size(); i++ ) { names[i] = plugins.get( i ).getName() + " : " + plugins.get( i ).getDescription(); } EnterSelectionDialog esd = new EnterSelectionDialog( shell, names, "Select a rule", "Select a new rule to add to the list:" ); String name = esd.open(); if ( name != null ) { try { int index = Const.indexOfString( name, names ); PluginInterface plugin = plugins.get( index ); ImportRuleInterface rule = (ImportRuleInterface) registry.loadClass( plugin ); rule.setEnabled( true ); rule.setId( plugin.getIds()[0] ); ImportRules newRules = new ImportRules(); getInfo( newRules ); newRules.getRules().add( rule ); importRules = newRules; // Refresh the whole list.. // getCompositesData(); } catch ( Exception e ) { new ErrorDialog( shell, "Error", "Error loading rule class", e ); } } } } public void removeRule() { MessageBox box = new MessageBox( shell, SWT.ICON_WARNING | SWT.APPLICATION_MODAL | SWT.SHEET | SWT.YES | SWT.NO ); box.setText( "Warning" ); box.setMessage( "Are you sure you want to remove the selected rules from the list?" ); int answer = box.open(); if ( answer != SWT.YES ) { return; } int[] indices = table.getSelectionIndices(); Arrays.sort( indices ); for ( int i = indices.length - 1; i >= 0; i-- ) { importRules.getRules().remove( indices[i] ); } // Refresh the whole list.. // getCompositesData(); } /** * Save the rules to an XML file */ protected void exportRules() { syncUIWithData(); FileDialog dialog = new FileDialog( shell, SWT.SAVE ); dialog.setFilterExtensions( new String[] { "*.xml;*.XML", "*" } ); dialog.setFilterNames( new String[] { BaseMessages.getString( PKG, "System.FileType.XMLFiles" ), BaseMessages.getString( PKG, "System.FileType.AllFiles" ) } ); if ( dialog.open() != null ) { String filename = dialog.getFilterPath() + System.getProperty( "file.separator" ) + dialog.getFileName(); FileWriter fileWriter = null; try { fileWriter = new FileWriter( filename ); fileWriter.write( XMLHandler.getXMLHeader() ); fileWriter.write( importRules.getXML() ); } catch ( Exception e ) { new ErrorDialog( shell, "Error", "There was an error while exporting to file '" + filename + "'", e ); } finally { try { fileWriter.close(); } catch ( Exception e ) { new ErrorDialog( shell, "Error", "There was an error closing file '" + filename + "'", e ); } } } } /** * Import the rules from an XML rules file... */ protected void importRules() { if ( !importRules.getRules().isEmpty() ) { MessageBox box = new MessageBox( shell, SWT.ICON_WARNING | SWT.APPLICATION_MODAL | SWT.SHEET | SWT.YES | SWT.NO ); box.setText( "Warning" ); box.setMessage( "Are you sure you want to load a new set of rules, replacing the current list?" ); int answer = box.open(); if ( answer != SWT.YES ) { return; } } FileDialog dialog = new FileDialog( shell, SWT.OPEN ); dialog.setFilterExtensions( new String[] { "*.xml;*.XML", "*" } ); dialog.setFilterNames( new String[] { BaseMessages.getString( PKG, "System.FileType.XMLFiles" ), BaseMessages.getString( PKG, "System.FileType.AllFiles" ) } ); if ( dialog.open() != null ) { String filename = dialog.getFilterPath() + System.getProperty( "file.separator" ) + dialog.getFileName(); ImportRules newRules = new ImportRules(); try { newRules.loadXML( XMLHandler.getSubNode( XMLHandler.loadXMLFile( filename ), ImportRules.XML_TAG ) ); importRules = newRules; // Re-load the dialog. // getCompositesData(); } catch ( Exception e ) { new ErrorDialog( shell, "Error", "There was an error during the import of the import rules file, verify the XML format.", e ); } } } protected void dispose() { shell.dispose(); } protected void cancel() { ok = false; dispose(); } protected void ok() { ok = true; getInfo( originalRules ); dispose(); } protected void getInfo( ImportRules ir ) { ir.getRules().clear(); for ( int i = 0; i < importRules.getRules().size(); i++ ) { ImportRuleInterface rule = importRules.getRules().get( i ); ImportRuleCompositeInterface importRuleComposite = compositesList.get( i ); TableItem tableItem = table.getItem( i ); importRuleComposite.getCompositeData( rule ); rule.setEnabled( tableItem.getChecked() ); ir.getRules().add( rule ); } } protected void syncUIWithData() { ImportRules newRules = new ImportRules(); getInfo( newRules ); importRules = newRules; getCompositesData(); } protected void getCompositesData() { for ( TableItem item : table.getItems() ) { item.dispose(); } table.clearAll(); // Fill the table items in the table with data from importRules: // compositesList = new ArrayList<ImportRuleCompositeInterface>(); for ( ImportRuleInterface rule : importRules.getRules() ) { try { TableItem item = new TableItem( table, SWT.NONE ); item.setChecked( rule.isEnabled() ); PluginRegistry registry = PluginRegistry.getInstance(); PluginInterface plugin = registry.getPlugin( ImportRulePluginType.class, rule ); item.setText( 1, Const.NVL( plugin.getName(), rule.getClass().getName() ) ); // Put a composite in the 3rd column... // // First get the composite generating class... // ImportRuleCompositeInterface importRuleComposite = getImportRuleComposite( rule ); compositesList.add( importRuleComposite ); final Composite composite = importRuleComposite.getComposite( table, rule ); composite.layout( true, true ); final TableEditor editor = new TableEditor( table ); editor.grabHorizontal = true; editor.grabVertical = true; editor.setEditor( composite, item, 2 ); // Put actual data onto the composite // importRuleComposite.setCompositeData( rule ); item.addDisposeListener( new DisposeListener() { public void widgetDisposed( DisposeEvent event ) { composite.dispose(); } } ); } catch ( Exception e ) { new ErrorDialog( shell, "Error", "Error displaying rule options for rule: " + rule.toString(), e ); compositesList.add( null ); } } } public ImportRuleCompositeInterface getImportRuleComposite( ImportRuleInterface rule ) throws KettleException { String compositeClassName = rule.getCompositeClassName(); Class<?> compositeClass; Class<?>[] paramClasses = new Class<?>[] {}; Object[] paramArgs = new Object[] {}; Constructor<?> compositeConstructor; try { compositeClass = rule.getClass().getClassLoader().loadClass( compositeClassName ); compositeConstructor = compositeClass.getConstructor( paramClasses ); return (ImportRuleCompositeInterface) compositeConstructor.newInstance( paramArgs ); } catch ( Exception e ) { throw new KettleException( e ); } } public static void main( String[] args ) throws Exception { Display display = new Display(); KettleEnvironment.init(); PropsUI.init( display, PropsUI.TYPE_PROPERTIES_SPOON ); Shell shell = new Shell( display ); ImportRules importRules = new ImportRules(); importRules.loadXML( XMLHandler.getSubNode( XMLHandler.loadXMLFile( "bin/import-rules.xml" ), ImportRules.XML_TAG ) ); ImportRulesDialog dialog = new ImportRulesDialog( shell, importRules ); if ( dialog.open() ) { for ( ImportRuleInterface rule : importRules.getRules() ) { System.out.println( " - " + rule.toString() ); } } } /* * (non-Javadoc) * * @see org.pentaho.ui.xul.impl.XulEventHandler#getData() */ public Object getData() { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.pentaho.ui.xul.impl.XulEventHandler#getName() */ public String getName() { return "importRules"; } /* * (non-Javadoc) * * @see org.pentaho.ui.xul.impl.XulEventHandler#getXulDomContainer() */ public XulDomContainer getXulDomContainer() { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.pentaho.ui.xul.impl.XulEventHandler#setData(java.lang.Object) */ public void setData( Object data ) { // TODO Auto-generated method stub } /* * (non-Javadoc) * * @see org.pentaho.ui.xul.impl.XulEventHandler#setName(java.lang.String) */ public void setName( String name ) { // TODO Auto-generated method stub } /* * (non-Javadoc) * * @see org.pentaho.ui.xul.impl.XulEventHandler#setXulDomContainer(org.pentaho.ui.xul.XulDomContainer) */ public void setXulDomContainer( XulDomContainer xulDomContainer ) { // TODO Auto-generated method stub } }