/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2017 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.repository.dialog; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.ShellAdapter; import org.eclipse.swt.events.ShellEvent; import org.eclipse.swt.graphics.Color; 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.Dialog; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; import org.pentaho.di.core.Const; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.repository.ObjectId; import org.pentaho.di.repository.Repository; import org.pentaho.di.repository.RepositoryDirectory; import org.pentaho.di.repository.RepositoryDirectoryInterface; import org.pentaho.di.repository.RepositoryElementMetaInterface; import org.pentaho.di.repository.RepositoryExtended; import org.pentaho.di.repository.RepositoryObjectType; import org.pentaho.di.ui.core.ConstUI; import org.pentaho.di.ui.core.PropsUI; import org.pentaho.di.ui.core.dialog.ErrorDialog; import org.pentaho.di.ui.core.gui.GUIResource; import org.pentaho.di.ui.core.gui.WindowProperty; import org.pentaho.di.ui.repository.RepositoryDirectoryUI; import org.pentaho.di.ui.trans.step.BaseStepDialog; import java.util.regex.Pattern; /** * Allows the user to make a selection of an Object in the repository * * @author Matt * @since 19-06-2003 */ public class SelectObjectDialog extends Dialog { private static Class<?> PKG = RepositoryDialogInterface.class; // for // i18n // purposes, // needed // by // Translator2!! private Label wlTree; private Tree wTree; private FormData fdlTree, fdTree, fdexpandAll; private Button wOK, wCancel; private Listener lsOK, lsCancel; private Shell shell; private SelectionAdapter lsDef; private String shellText; private String lineText; private PropsUI props; private Color dircolor; private Repository rep; private String objectName; private RepositoryDirectoryInterface objectDirectory; private TreeColumn nameColumn; private TreeColumn userColumn; private TreeColumn changedColumn; private int sortColumn; private boolean ascending; private TreeColumn typeColumn; private RepositoryObjectType objectType; private boolean showTrans; private boolean showJobs; private TreeColumn descriptionColumn; private ToolItem expandAll, collapseAll, goSearch, wfilter; private String filterString = null; private Text searchText = null; private Pattern pattern = null; private RepositoryDirectoryInterface directoryTree; // private RepositoryCapabilities capabilities; private boolean includeDeleted; private ToolItem wbRegex; private RepositoryElementMetaInterface repositoryObject; private ObjectId objectId; public SelectObjectDialog( Shell parent, Repository rep ) { this( parent, rep, true, true ); } public SelectObjectDialog( Shell parent, Repository rep, boolean showTransformations, boolean showJobs ) { super( parent, SWT.NONE ); this.props = PropsUI.getInstance(); this.rep = rep; this.showTrans = showTransformations; this.showJobs = showJobs; // TODO: make this a configuration option in the dialog! // this.includeDeleted = false; shellText = BaseMessages.getString( PKG, "SelectObjectDialog.Dialog.Main.Title" ); lineText = BaseMessages.getString( PKG, "SelectObjectDialog.Dialog.Object.Title" ); objectName = null; objectDirectory = null; sortColumn = 0; ascending = false; } @SuppressWarnings( "deprecation" ) public String open() { Shell parent = getParent(); dircolor = GUIResource.getInstance().getColorDirectory(); shell = new Shell( parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.SHEET | SWT.RESIZE | SWT.MIN | SWT.MAX ); props.setLook( shell ); shell.setImage( GUIResource.getInstance().getImageSpoon() ); FormLayout formLayout = new FormLayout(); formLayout.marginWidth = Const.FORM_MARGIN; formLayout.marginHeight = Const.FORM_MARGIN; shell.setLayout( formLayout ); shell.setText( shellText ); int margin = Const.MARGIN; ToolBar treeTb = new ToolBar( shell, SWT.HORIZONTAL | SWT.FLAT ); props.setLook( treeTb ); wfilter = new ToolItem( treeTb, SWT.SEPARATOR ); searchText = new Text( treeTb, SWT.SEARCH | SWT.CANCEL ); searchText.setToolTipText( BaseMessages .getString( PKG, "RepositoryExplorerDialog.Search.FilterString.ToolTip" ) ); wfilter.setControl( searchText ); wfilter.setWidth( 100 ); wbRegex = new ToolItem( treeTb, SWT.CHECK ); wbRegex.setImage( GUIResource.getInstance().getImageRegexSmall() ); wbRegex.setToolTipText( BaseMessages.getString( PKG, "RepositoryExplorerDialog.Search.UseRegex" ) ); goSearch = new ToolItem( treeTb, SWT.PUSH ); goSearch.setImage( GUIResource.getInstance().getImageSearchSmall() ); goSearch.setToolTipText( BaseMessages.getString( PKG, "RepositoryExplorerDialog.Search.Run" ) ); expandAll = new ToolItem( treeTb, SWT.PUSH ); expandAll.setImage( GUIResource.getInstance().getImageExpandAll() ); collapseAll = new ToolItem( treeTb, SWT.PUSH ); collapseAll.setImage( GUIResource.getInstance().getImageCollapseAll() ); fdexpandAll = new FormData(); fdexpandAll.right = new FormAttachment( 100, -margin ); fdexpandAll.top = new FormAttachment( 0, margin ); treeTb.setLayoutData( fdexpandAll ); // From step line wlTree = new Label( shell, SWT.NONE ); wlTree.setText( lineText ); props.setLook( wlTree ); fdlTree = new FormData(); fdlTree.left = new FormAttachment( 0, 0 ); fdlTree.top = new FormAttachment( 0, margin ); wlTree.setLayoutData( fdlTree ); wTree = new Tree( shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL ); wTree.setHeaderVisible( true ); props.setLook( wTree ); // Add some columns to it as well... nameColumn = new TreeColumn( wTree, SWT.LEFT ); nameColumn.setText( BaseMessages.getString( PKG, "RepositoryExplorerDialog.Column.Name" ) ); nameColumn.setWidth( 350 ); nameColumn.addListener( SWT.Selection, new Listener() { public void handleEvent( Event e ) { setSort( 0 ); } } ); // No sorting on the type column just yet. typeColumn = new TreeColumn( wTree, SWT.LEFT ); typeColumn.setText( BaseMessages.getString( PKG, "RepositoryExplorerDialog.Column.Type" ) ); typeColumn.setWidth( 100 ); typeColumn.addListener( SWT.Selection, new Listener() { public void handleEvent( Event e ) { setSort( 1 ); } } ); userColumn = new TreeColumn( wTree, SWT.LEFT ); userColumn.setText( BaseMessages.getString( PKG, "RepositoryExplorerDialog.Column.User" ) ); userColumn.setWidth( 100 ); userColumn.addListener( SWT.Selection, new Listener() { public void handleEvent( Event e ) { setSort( 2 ); } } ); changedColumn = new TreeColumn( wTree, SWT.LEFT ); changedColumn.setText( BaseMessages.getString( PKG, "RepositoryExplorerDialog.Column.Changed" ) ); changedColumn.setWidth( 120 ); changedColumn.addListener( SWT.Selection, new Listener() { public void handleEvent( Event e ) { setSort( 3 ); } } ); descriptionColumn = new TreeColumn( wTree, SWT.LEFT ); descriptionColumn.setText( BaseMessages.getString( PKG, "RepositoryExplorerDialog.Column.Description" ) ); descriptionColumn.setWidth( 120 ); descriptionColumn.addListener( SWT.Selection, new Listener() { public void handleEvent( Event e ) { setSort( 4 ); } } ); props.setLook( wTree ); fdTree = new FormData(); fdTree.left = new FormAttachment( 0, 0 ); fdTree.right = new FormAttachment( 100, 0 ); fdTree.top = new FormAttachment( treeTb, margin ); fdTree.bottom = new FormAttachment( 100, -30 ); wTree.setLayoutData( fdTree ); // Some buttons wOK = new Button( shell, SWT.PUSH ); wOK.setText( BaseMessages.getString( PKG, "System.Button.OK" ) ); lsOK = new Listener() { public void handleEvent( Event e ) { ok(); } }; wOK.addListener( SWT.Selection, lsOK ); wOK.setEnabled( false ); wCancel = new Button( shell, SWT.PUSH ); wCancel.setText( BaseMessages.getString( PKG, "System.Button.Cancel" ) ); lsCancel = new Listener() { public void handleEvent( Event e ) { cancel(); } }; wCancel.addListener( SWT.Selection, lsCancel ); BaseStepDialog.positionBottomButtons( shell, new Button[] { wOK, wCancel }, margin, null ); // Add listeners lsDef = new SelectionAdapter() { public void widgetDefaultSelected( SelectionEvent e ) { ok(); } }; wTree.addSelectionListener( lsDef ); wTree.addKeyListener( new KeyAdapter() { public void keyPressed( KeyEvent e ) { if ( e.character == SWT.CR ) { ok(); } } } ); wTree.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent e ) { if ( wTree.getSelection().length > 0 ) { wOK.setEnabled( !Boolean.TRUE.equals( wTree.getSelection()[ 0 ].getData( "isFolder" ) ) ); } } } ); expandAll.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { expandAllItems( wTree.getItems(), true ); } } ); collapseAll.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { expandAllItems( wTree.getItems(), false ); } } ); goSearch.addSelectionListener( new SelectionAdapter() { public void widgetSelected( SelectionEvent event ) { updateFilter(); } } ); searchText.addSelectionListener( new SelectionAdapter() { public void widgetDefaultSelected( SelectionEvent e ) { updateFilter(); } } ); // Detect [X] or ALT-F4 or something that kills this window... shell.addShellListener( new ShellAdapter() { public void shellClosed( ShellEvent e ) { cancel(); } } ); try { if ( rep instanceof RepositoryExtended ) { RepositoryExtended repositoryExtended = (RepositoryExtended) this.rep; directoryTree = repositoryExtended.loadRepositoryDirectoryTree( "/", "*.kjb|*.ktr", -1, true, true, false ); } else { directoryTree = this.rep.loadRepositoryDirectoryTree(); } } catch ( KettleException e ) { new ErrorDialog( shell, BaseMessages.getString( PKG, "SelectObjectDialog.Dialog.ErrorRefreshingDirectoryTree.Title" ), BaseMessages.getString( PKG, "SelectObjectDialog.Dialog.ErrorRefreshingDirectoryTree.Message" ), e ); } // catch() getData(); wTree.setFocus(); BaseStepDialog.setSize( shell ); shell.open(); while ( !shell.isDisposed() ) { if ( !shell.getDisplay().readAndDispatch() ) { shell.getDisplay().sleep(); } } return objectName; } private void expandAllItems( TreeItem[] treeitems, boolean expand ) { for ( TreeItem item : treeitems ) { item.setExpanded( expand ); if ( item.getItemCount() > 0 ) { expandAllItems( item.getItems(), expand ); } } } protected void updateFilter() { pattern = null; filterString = null; if ( searchText != null && !searchText.isDisposed() && !Utils.isEmpty( searchText.getText() ) ) { if ( wbRegex.getSelection() ) { pattern = Pattern.compile( searchText.getText() ); } else { filterString = searchText.getText().toUpperCase(); } } refreshTree(); if ( ( wbRegex.getSelection() && pattern != null ) || ( !wbRegex.getSelection() && filterString != null ) ) { while ( getNrEmptyFolders( wTree.getItems() ) > 0 ) { removeEmptyFolders( wTree.getItems() ); try { Thread.sleep( 0, 1 ); } catch ( InterruptedException e ) { // Ignore errors } } expandAllItems( wTree.getItems(), true ); } } private void removeEmptyFolders( TreeItem[] treeitems ) { for ( TreeItem item : treeitems ) { if ( item.getImage().equals( GUIResource.getInstance().getImageArrow() ) && item.getItemCount() == 0 ) { item.dispose(); } else { removeEmptyFolders( item.getItems() ); } } } private int getNrEmptyFolders( TreeItem[] treeitems ) { int retval = 0; for ( TreeItem item : treeitems ) { if ( item.getImage().equals( GUIResource.getInstance().getImageArrow() ) && item.getItemCount() == 0 ) { retval++; } else { retval += getNrEmptyFolders( item.getItems() ); } } return retval; } protected void setSort( int i ) { if ( sortColumn == i ) { ascending = !ascending; } else { sortColumn = i; ascending = true; } if ( sortColumn >= 0 && sortColumn < 5 ) { TreeColumn column = wTree.getColumn( sortColumn ); wTree.setSortColumn( column ); wTree.setSortDirection( ascending ? SWT.UP : SWT.DOWN ); } refreshTree(); } private void refreshTree() { try { wTree.removeAll(); TreeItem ti = null; // If the directory is a root directory and is visible to the user we will // display that on the UI otherwise we will hide it if ( directoryTree.isRoot() && directoryTree.isVisible() ) { ti = new TreeItem( wTree, SWT.NONE ); ti.setImage( GUIResource.getInstance().getImageFolder() ); ti.setExpanded( true ); RepositoryDirectoryUI.getTreeWithNames( ti, rep, dircolor, sortColumn, includeDeleted, ascending, showTrans, showJobs, directoryTree, filterString, pattern ); } else { for ( int i = 0; i < directoryTree.getNrSubdirectories(); i++ ) { RepositoryDirectory subdir = directoryTree.getSubdirectory( i ); ti = new TreeItem( wTree, SWT.NONE ); ti.setImage( GUIResource.getInstance().getImageFolder() ); RepositoryDirectoryUI.getTreeWithNames( ti, rep, dircolor, sortColumn, includeDeleted, ascending, showTrans, showJobs, subdir, filterString, pattern ); } } } catch ( KettleException e ) { new ErrorDialog( shell, BaseMessages.getString( PKG, "SelectObjectDialog.Dialog.UnexpectedError.Title" ), BaseMessages .getString( PKG, "SelectObjectDialog.Dialog.UnexpectedError.Message" ), e ); } } public void dispose() { props.setScreen( new WindowProperty( shell ) ); shell.dispose(); } public void getData() { setSort( 0 ); } private void cancel() { objectName = null; dispose(); } private void ok() { // Something has to be selected! if ( wTree.getSelectionCount() > 0 ) { TreeItem ti = wTree.getSelection()[ 0 ]; // No directory! if ( !Boolean.TRUE.equals( wTree.getSelection()[ 0 ].getData( "isFolder" ) ) ) { int level = ConstUI.getTreeLevel( ti ); if ( level > 0 ) { repositoryObject = (RepositoryElementMetaInterface) ti.getData(); if ( repositoryObject != null ) { objectName = repositoryObject.getName(); objectDirectory = repositoryObject.getRepositoryDirectory(); objectId = repositoryObject.getObjectId(); objectType = repositoryObject.getObjectType(); } else { // For backward compatibility, we should rarely end up here... // String[] path = ConstUI.getTreeStrings( ti.getParentItem() ); objectName = ti.getText( 0 ); objectType = null; for ( RepositoryObjectType type : RepositoryObjectType.values() ) { if ( type.getTypeDescription().equalsIgnoreCase( ti.getText( 1 ) ) ) { objectType = type; break; } } objectDirectory = directoryTree.findDirectory( path ); } if ( objectDirectory != null ) { dispose(); } else { MessageBox mb = new MessageBox( shell, SWT.OK | SWT.ICON_ERROR ); mb.setMessage( BaseMessages.getString( PKG, "SelectObjectDialog.Dialog.DirectoryNotFound.Message" ) ); mb.setText( BaseMessages.getString( PKG, "SelectObjectDialog.Dialog.DirectoryNotFound.Title" ) ); mb.open(); } } } } } public RepositoryDirectoryInterface getDirectory() { return objectDirectory; } /** * @return the objectType */ public RepositoryObjectType getObjectType() { return objectType; } /** * @return the objectName */ public String getObjectName() { return objectName; } /** * @return the repositoryObject */ public RepositoryElementMetaInterface getRepositoryObject() { return repositoryObject; } /** * @param repositoryObject the repositoryObject to set */ public void setRepositoryObject( RepositoryElementMetaInterface repositoryObject ) { this.repositoryObject = repositoryObject; } /** * @return the objectId */ public ObjectId getObjectId() { return objectId; } /** * @param objectId the objectId to set */ public void setObjectId( ObjectId objectId ) { this.objectId = objectId; } }