/*
* Licensed to "Neo Technology," Network Engine for Objects in Lund AB
* (http://neotechnology.com) under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Neo Technology licenses this file to you 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.neo4j.neoclipse.reltype;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.NotFoundException;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.neoclipse.Activator;
import org.neo4j.neoclipse.event.NeoclipseEvent;
import org.neo4j.neoclipse.event.NeoclipseEventListener;
import org.neo4j.neoclipse.event.NeoclipseListenerList;
import org.neo4j.neoclipse.graphdb.GraphCallable;
import org.neo4j.neoclipse.graphdb.GraphDbUtil;
import org.neo4j.neoclipse.view.ErrorMessage;
import org.neo4j.neoclipse.view.NeoGraphLabelProviderWrapper;
/**
* Provide (filtered) relationship types. Initial clients: Database graph view
* and Relationship types view.
*
* @author anders
*/
public class RelationshipTypesProvider implements IContentProvider,
IStructuredContentProvider
{
private class ReltypeCtrlChangeListener implements NeoclipseEventListener
{
public void stateChanged( final NeoclipseEvent event )
{
notifyFilterListeners( event );
}
}
private boolean viewAll = true;
private final Set<RelationshipType> fakeTypes = new RelationshipTypeHashSet();
private Set<RelationshipType> currentRelTypes = Collections.emptySet();
private final Map<RelationshipType, RelationshipTypeControl> currentRelTypeCtrls = new RelationshipTypeHashMap<RelationshipTypeControl>();
private final NeoclipseListenerList filterListeners = new NeoclipseListenerList();
private final NeoclipseListenerList typesListeners = new NeoclipseListenerList();
private final ReltypeCtrlChangeListener reltypeCtrlChangeListener = new ReltypeCtrlChangeListener();
private final NeoclipseListenerList refreshListeners = new NeoclipseListenerList();
/**
* Factory method that creates relationship type items for the table view.
*
* @param relType the relationship type to wrap
* @return
*/
public RelationshipTypeControl createRelationshipTypeControl(
final RelationshipType relType )
{
RelationshipTypeControl relTypeCtrl = new RelationshipTypeControl(
relType );
relTypeCtrl.addChangeListener( reltypeCtrlChangeListener );
return relTypeCtrl;
}
/**
* Get all relationship types. If the viewAll attribute is set to false only
* the relationship types that was handled in the current database graph
* view will be returned.
*/
public Object[] getElements( final Object inputElement )
{
if ( viewAll )
{
currentRelTypes = getRelationshipTypesFromDb();
currentRelTypes.addAll( fakeTypes );
}
else
{
currentRelTypes = NeoGraphLabelProviderWrapper.getInstance().getRelationshipTypes();
currentRelTypes.addAll( fakeTypes );
}
refreshListeners.notifyListeners( new NeoclipseEvent( this ) );
for ( RelationshipType relType : currentRelTypes )
{
// only add if it's not already there
if ( !currentRelTypeCtrls.containsKey( relType ) )
{
currentRelTypeCtrls.put( relType,
createRelationshipTypeControl( relType ) );
}
}
return currentRelTypeCtrls.values().toArray();
}
/**
* Get all relationship types in the database.
*
* @return
*/
public Set<RelationshipType> getRelationshipTypesFromDb()
{
try
{
return Activator.getDefault().getGraphDbServiceManager().submitTask(
new GraphCallable<Set<RelationshipType>>()
{
public Set<RelationshipType> call(
final GraphDatabaseService graphDb )
{
return GraphDbUtil.getRelationshipTypesFromDb( graphDb );
}
}, "get relationship types" ).get();
}
catch ( Exception e )
{
ErrorMessage.showDialog( "Listing relationship types", e );
}
return Collections.emptySet();
}
/**
* Get all relationship types in the database and additional "fake" types.
*
* @return
*/
public Set<RelationshipType> getCurrentRelationshipTypes()
{
return currentRelTypes;
}
/**
* Add a "fake" relationship type. It will be persisted to the database upon
* usage (creating a relationship of this type).
*
* @param name the name of the relationship type
*/
public RelationshipType addFakeType( final String name )
{
RelationshipType relType = DynamicRelationshipType.withName( name );
fakeTypes.add( relType );
notifyTypesListeners( new NeoclipseEvent( relType ) );
return relType;
}
/**
* Get the table items corresponding to a collection of relationship types.
*
* @param relTypes the relationship types to select
* @return the relationship type controls that are used in the table
*/
Collection<RelationshipTypeControl> getFilteredRelTypeControls(
final Collection<RelationshipType> relTypes )
{
Collection<RelationshipTypeControl> relTypeCtrls = new ArrayList<RelationshipTypeControl>();
for ( RelationshipType relType : relTypes )
{
RelationshipTypeControl relTypeCtrl = currentRelTypeCtrls.get( relType );
if ( relTypeCtrl != null )
{
relTypeCtrls.add( relTypeCtrl );
}
}
return Collections.unmodifiableCollection( relTypeCtrls );
}
/**
* Get relationship types and direction from current filterset.
*
* @return an array of RelationshipType and Direction (alternating)
*/
public List<Object> getFilteredRelTypesDirections()
{
if ( currentRelTypeCtrls.isEmpty() )
{
throw new NotFoundException();
}
List<Object> relDirList = new ArrayList<Object>();
for ( RelationshipTypeControl relTypeCtrl : currentRelTypeCtrls.values() )
{
if ( relTypeCtrl.hasDirection() )
{
relDirList.add( relTypeCtrl.getRelType() );
relDirList.add( relTypeCtrl.getDirection() );
}
}
return relDirList;
}
public Collection<RelationshipTypeControl> getFilteredDirectedRelationships()
{
if ( currentRelTypeCtrls.isEmpty() )
{
throw new NotFoundException();
}
return currentRelTypeCtrls.values();
}
/**
* Set all relationship types to the same filtering.
*
* @param in state for incoming relationships
* @param out state for outgoing relationships
*/
public void setAllFilters( final boolean in, final boolean out )
{
filterListeners.setInhibit( true );
for ( RelationshipType relType : currentRelTypeCtrls.keySet() )
{
RelationshipTypeControl relTypeCtrl = currentRelTypeCtrls.get( relType );
if ( relTypeCtrl != null )
{
relTypeCtrl.setIn( in );
relTypeCtrl.setOut( out );
}
}
filterListeners.setInhibit( false );
notifyFilterListeners( new NeoclipseEvent( this ) );
}
public void refresh()
{
fakeTypes.clear();
currentRelTypes.clear();
currentRelTypeCtrls.clear();
}
public void dispose()
{
}
public void inputChanged( final Viewer viewer, final Object oldInput,
final Object newInput )
{
}
/**
* Set provider to return all existing relationship types.
*/
public void setViewAll()
{
viewAll = true;
}
/**
* Set provider to only return relationship types currently used in the
* database graph view.
*/
public void setViewTraversed()
{
viewAll = false;
}
/**
* Notify listeners something changed in the relationship type filters.
*
* @param event
*/
private void notifyFilterListeners( final NeoclipseEvent event )
{
filterListeners.notifyListeners( event );
}
/**
* Add listener to relationship types filter changes.
*
* @param newListener
*/
public void addFilterStatusListener(
final NeoclipseEventListener newListener )
{
filterListeners.add( newListener );
}
/**
* Add listener to relationship type (e.g. addition) changes.
*
* @param newListener
*/
public void addTypeChangeListener( final NeoclipseEventListener newListener )
{
typesListeners.add( newListener );
}
/**
* Notify listeners something changed in the relationship types.
*
* @param event
*/
private void notifyTypesListeners( final NeoclipseEvent event )
{
typesListeners.notifyListeners( event );
}
/**
* Add listener to complete refresh events.
*
* @param newListener
*/
public void addTypeRefreshListener( final NeoclipseEventListener newListener )
{
refreshListeners.add( newListener );
}
}