/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* 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.kie.workbench.common.screens.explorer.client.widgets.navigator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.client.ui.Composite;
import org.guvnor.structure.client.resources.NavigatorResources;
import org.kie.workbench.common.screens.explorer.client.resources.i18n.ProjectExplorerConstants;
import org.kie.workbench.common.screens.explorer.client.widgets.BaseViewPresenter;
import org.kie.workbench.common.screens.explorer.model.FolderItem;
import org.kie.workbench.common.screens.explorer.model.FolderItemType;
import org.kie.workbench.common.screens.explorer.model.FolderListing;
import org.uberfire.backend.vfs.Path;
import org.uberfire.ext.widgets.core.client.tree.Tree;
import org.uberfire.ext.widgets.core.client.tree.TreeItem;
import org.uberfire.workbench.type.DotResourceTypeDefinition;
import static org.uberfire.commons.validation.PortablePreconditions.*;
@Dependent
public class TreeNavigator extends Composite implements Navigator {
private static final String LAZY_LOAD = ProjectExplorerConstants.INSTANCE.LoadingDotDotDot();
@Inject
private DotResourceTypeDefinition hiddenTypeDef;
private NavigatorOptions options = new NavigatorOptions();
private final Tree tree = new Tree();
private BaseViewPresenter presenter;
private FolderListing activeContent;
@PostConstruct
public void init() {
tree.addStyleName( NavigatorResources.INSTANCE.css().treeNav() );
initWidget( tree );
tree.addOpenHandler( new OpenHandler<TreeItem>() {
@Override
public void onOpen( final OpenEvent<TreeItem> event ) {
if ( needsLoading( event.getTarget() ) ) {
presenter.loadContent( (FolderItem) event.getTarget().getUserObject() );
}
}
} );
tree.addSelectionHandler( new SelectionHandler<TreeItem>() {
@Override
public void onSelection( SelectionEvent<TreeItem> event ) {
if ( event.getSelectedItem().getUserObject() != null && event.getSelectedItem().getUserObject() instanceof FolderItem ) {
presenter.onItemSelected( ( FolderItem ) event.getSelectedItem().getUserObject() );
}
}
} );
}
@Override
public void setOptions( final NavigatorOptions options ) {
this.options = options;
}
@Override
public void loadContent( final FolderListing content ) {
loadContent( content,
new HashMap<FolderItem, List<FolderItem>>() );
}
@Override
public void loadContent( final FolderListing content,
final Map<FolderItem, List<FolderItem>> siblings ) {
if ( content == null || content.getItem() == null ) {
clear();
return;
}
if ( content.equals( activeContent ) ) {
if ( tree.getSelectedItem() != null ) {
tree.getSelectedItem().setState( TreeItem.State.OPEN,
true,
false );
}
return;
}
this.activeContent = content;
TreeItem item = null;
if ( !tree.isEmpty() ) {
item = findItemInTree( content.getItem() );
}
if ( item == null ) {
if ( content.getSegments().isEmpty() ) {
final FolderItem rootItem = content.getItem();
item = new TreeItem( TreeItem.Type.FOLDER,
rootItem.getFileName().replaceAll( " ",
"\u00a0" ) );
tree.addItem( item );
item.setUserObject( rootItem );
} else {
final TreeItem parent = loadRoots( content.getSegments(),
siblings );
if ( parent != null ) {
item = loadSiblings( content.getItem(),
new TreeNavigatorItemImpl( parent ),
siblings );
if ( item != null ) {
item.setUserObject( content.getItem() );
}
}
}
}
if ( item != null ) {
item.setState( TreeItem.State.OPEN,
true,
false );
tree.setSelectedItem( item );
item.removeItems();
loadContent( new TreeNavigatorItemImpl( item ),
content );
}
}
private TreeItem findItemInTree( final FolderItem xxx ) {
TreeItem item = null;
for ( final TreeItem treeItem : tree.getItems() ) {
if ( item != null ) {
return item;
}
if ( xxx != null && xxx.equals( treeItem.getUserObject() ) ) {
item = treeItem;
} else {
item = findItemInChildren( treeItem, xxx );
}
}
return item;
}
private TreeItem loadRoots( final List<FolderItem> segments,
final Map<FolderItem, List<FolderItem>> siblings ) {
TreeItem parent = null;
for ( final FolderItem segment : segments ) {
TreeItem item;
if ( tree.isEmpty() ) {
item = new TreeItem( TreeItem.Type.FOLDER,
segment.getFileName().replaceAll( " ",
"\u00a0" ) );
item.setUserObject( segment );
tree.addItem( item );
parent = item;
} else {
if ( parent == null ) {
parent = findItemInTree( segment );
} else {
item = findItemInTree( segment );
if ( item == null ) {
item = loadSiblings( segment,
new TreeNavigatorItemImpl( parent ),
siblings );
if ( item != null ) {
item.setUserObject( segment );
}
} else if ( needsLoading( item ) ) {
item.getChild( 0 ).getElement().getStyle().setDisplay( Style.Display.NONE );
}
parent = item;
}
}
}
return parent;
}
private TreeItem loadSiblings( final FolderItem item,
final TreeNavigatorItemImpl parent,
final Map<FolderItem, List<FolderItem>> siblings ) {
final List<FolderItem> mySiblings = siblings.get( item );
if ( mySiblings != null && !mySiblings.isEmpty() ) {
for ( final FolderItem sibling : new ArrayList<FolderItem>( mySiblings ) ) {
final TreeItem existingSibling = findItemInChildren( parent.parent,
sibling );
if ( existingSibling == null ) {
if ( sibling.getType().equals( FolderItemType.FOLDER ) ) {
parent.addDirectory( sibling );
} else {
parent.addFile( sibling );
}
mySiblings.remove( sibling );
}
}
if ( mySiblings.isEmpty() ) {
siblings.remove( item );
}
}
return findItemInChildren( parent.parent,
item );
}
private TreeItem findItemInChildren( final TreeItem item,
final FolderItem target ) {
TreeItem result = null;
for ( final TreeItem treeItem : item.getChildren() ) {
if ( result != null ) {
break;
}
if ( target != null && target.equals( treeItem.getUserObject() ) ) {
result = treeItem;
} else {
result = findItemInChildren( treeItem, target );
}
}
return result;
}
@Override
public void clear() {
tree.clear();
activeContent = null;
}
@Override
public void setPresenter( final BaseViewPresenter presenter ) {
this.presenter = presenter;
}
private void loadContent( final NavigatorItem parent,
final FolderListing content ) {
if ( content != null ) {
for ( final FolderItem folderItem : content.getContent() ) {
if ( folderItem.getType().equals( FolderItemType.FOLDER ) ) {
if ( options.showDirectories() ) {
parent.addDirectory( folderItem );
}
} else {
if ( options.showFiles() ) {
if ( !options.showHiddenFiles() && !isHidden( folderItem ) ) {
parent.addFile( folderItem );
} else {
parent.addFile( folderItem );
}
}
}
}
parent.cleanup();
}
}
private boolean isHidden( final FolderItem folderItem ) {
return hiddenTypeDef.accept( new Path() {
@Override
public String getFileName() {
return folderItem.getFileName();
}
@Override
public String toURI() {
return null;
}
@Override
public int compareTo( final Path path ) {
return 0;
}
} );
}
private boolean needsLoading( final TreeItem item ) {
return item.getChildCount() == 1 && LAZY_LOAD.equals( item.getChild( 0 ).getText() );
}
private class TreeNavigatorItemImpl implements NavigatorItem {
private final TreeItem parent;
TreeNavigatorItemImpl( final TreeItem treeItem ) {
this.parent = checkNotNull( "parent", treeItem );
}
public void addDirectory( final FolderItem child ) {
checkCleanupLoading();
for ( final TreeItem treeItem : parent.getChildren() ) {
if ( treeItem.getUserObject() != null && treeItem.getUserObject().equals( child ) ) {
return;
}
}
final TreeItem newDirectory = parent.addItem( TreeItem.Type.FOLDER, child.getFileName().replaceAll( " ", "\u00a0" ) );
newDirectory.addItem( TreeItem.Type.LOADING, LAZY_LOAD );
newDirectory.setUserObject( child );
}
public void addFile( final FolderItem child ) {
checkCleanupLoading();
for ( final TreeItem treeItem : parent.getChildren() ) {
if ( treeItem.getUserObject() != null && treeItem.getUserObject().equals( child ) ) {
return;
}
}
final TreeItem newFile = parent.addItem( TreeItem.Type.ITEM, child.getFileName().replaceAll( " ", "\u00a0" ) );
newFile.setUserObject( child );
}
@Override
public void cleanup() {
checkCleanupLoading();
}
public void checkCleanupLoading() {
if ( parent.getChild( 0 ) != null && parent.getChild( 0 ).getUserObject() == null ) {
parent.getChild( 0 ).remove();
}
}
}
}