/*
* 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.property;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.draw2d.ChangeEvent;
import org.eclipse.draw2d.ChangeListener;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.INullSelectionListener;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.views.properties.IPropertySourceProvider;
import org.eclipse.ui.views.properties.PropertySheetEntry;
import org.eclipse.ui.views.properties.PropertySheetPage;
import org.eclipse.ui.views.properties.PropertySheetSorter;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.neoclipse.Icons;
import org.neo4j.neoclipse.help.HelpContextConstants;
import org.neo4j.neoclipse.property.action.AddNodeLabelAction;
import org.neo4j.neoclipse.property.action.CopyAction;
import org.neo4j.neoclipse.property.action.DeleteAction;
import org.neo4j.neoclipse.property.action.NewAction;
import org.neo4j.neoclipse.property.action.PasteAction;
import org.neo4j.neoclipse.property.action.RenameAction;
import org.neo4j.neoclipse.view.NeoGraphViewPart;
import org.neo4j.neoclipse.view.UiHelper;
/**
* This class is a workaround to sort the property categories in the way we
* want.
*
* @author Anders Nawroth
*/
public class NeoPropertySheetPage extends PropertySheetPage implements
ISelectionListener, INullSelectionListener
{
private static class NeoPropertySheetSorter extends PropertySheetSorter
{
private static final String RELATIONSHIP = "Relationship";
@Override
public int compareCategories( final String categoryA,
final String categoryB )
{
if ( RELATIONSHIP.equals( categoryA )
|| RELATIONSHIP.equals( categoryB ) )
{
// reverse the categories in this case
return super.compareCategories( categoryB, categoryA );
}
return super.compareCategories( categoryA, categoryB );
}
}
/**
* The Eclipse view ID.
*/
public static final String ID = "org.neo4j.neoclipse.property.NeoPropertySheetPage";
private ISelection selection;
private Menu menu;
private Composite parent;
private DeleteAction deleteAction;
private CopyAction copyAction;
private RenameAction renameAction;
private PasteAction pasteAction;
private PropertyContainer containerSelection;
private final List<ChangeListener> listeners = new ArrayList<ChangeListener>();
private AddNodeLabelAction addNodeLabelAction;
public NeoPropertySheetPage()
{
super();
setPropertySourceProvider( new PropertySourceProvider( this ) );
}
public void addChangeListener( final ChangeListener listener )
{
listeners.add( listener );
}
public void fireChangeEvent( final Object element, final String key,
final boolean refresh )
{
// TODO make sure this key gets selected in the view
ChangeEvent ce = new ChangeEvent( element, key );
for ( ChangeListener listener : listeners )
{
listener.handleStateChanged( ce );
}
if ( refresh )
{
refreshSafely();
}
}
public void refreshSafely()
{
UiHelper.asyncExec( new Runnable()
{
public void run()
{
refresh();
}
} );
}
public PropertyContainer getPropertyContainer()
{
return containerSelection;
}
/**
* Get the current selection.
*
* @return current selection
*/
public ISelection getSelection()
{
return selection;
}
@Override
public void createControl( final Composite parent )
{
super.createControl( parent );
this.parent = parent;
setSorter( new NeoPropertySheetSorter() );
createMenu( parent );
getControl().setMenu( menu );
getSite().getPage().addSelectionListener( NeoGraphViewPart.ID, this );
PlatformUI.getWorkbench().getHelpSystem().setHelp( parent,
HelpContextConstants.NEO_PROPERTY_SHEET_PAGE );
}
/**
* Create the context menu for this property sheet.
*
* @param parent
*/
private void createMenu( final Composite parent )
{
MenuManager menuManager = createMainMenu( parent );
menu = menuManager.createContextMenu( getControl() );
MenuManager addMenuManager = createNewSubmenu( parent );
addMenuManager.setParent( menuManager );
menuManager.add( addMenuManager );
MenuManager addArrayMenuManager = createNewArraySubmenu( parent );
addArrayMenuManager.setParent( menuManager );
menuManager.add( addArrayMenuManager );
}
/**
* Create the main structure of the menu.
*/
private MenuManager createMainMenu( final Composite parent )
{
MenuManager menuMgr = new MenuManager();
copyAction = new CopyAction( parent, this );
menuMgr.add( copyAction );
pasteAction = new PasteAction( parent, this );
pasteAction.setEnabled( false );
menuMgr.add( pasteAction );
deleteAction = new DeleteAction( parent, this );
menuMgr.add( deleteAction );
renameAction = new RenameAction( parent, this );
menuMgr.add( renameAction );
addNodeLabelAction = new AddNodeLabelAction( parent, this );
menuMgr.add( addNodeLabelAction );
return menuMgr;
}
/**
* Enable paste action.
*/
public void enablePaste()
{
pasteAction.setEnabled( true );
}
/**
* Enable/disable actions that operate on an existing property.
*
* @param enabled
*/
private void setRestrictedEnabled( final boolean enabled )
{
if ( deleteAction != null )
{
deleteAction.setEnabled( enabled );
}
if ( copyAction != null )
{
copyAction.setEnabled( enabled );
}
if ( renameAction != null )
{
renameAction.setEnabled( enabled );
}
if ( addNodeLabelAction != null )
{
addNodeLabelAction.setEnabled( enabled );
}
}
/**
* Create submenu for adding new properties.
*/
private MenuManager createNewSubmenu( final Composite parent )
{
MenuManager addMenuMgr = new MenuManager( "New",
Icons.NEW_ENABLED.descriptor(), "propertiesAddSubmenu" );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( String.class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( Character.class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( Long.class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( Integer.class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( Short.class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( Byte.class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( Double.class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( Float.class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( Boolean.class ) ) );
return addMenuMgr;
}
/**
* Create submenu for adding new properties of array type.
*/
private MenuManager createNewArraySubmenu( final Composite parent )
{
MenuManager addMenuMgr = new MenuManager( "New[]",
Icons.NEW_ENABLED.descriptor(), "propertiesArrayAddSubmenu" );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( String[].class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( char[].class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( long[].class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( int[].class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( short[].class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( byte[].class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( double[].class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( float[].class ) ) );
addMenuMgr.add( new NewAction( parent, this,
PropertyTransform.getHandler( boolean[].class ) ) );
return addMenuMgr;
}
@Override
public void handleEntrySelection( final ISelection selection )
{
super.handleEntrySelection( selection );
this.selection = selection;
if ( selection instanceof IStructuredSelection )
{
IStructuredSelection ss = (IStructuredSelection) selection;
if ( ss.size() > 1 )
{
setRestrictedEnabled( false );
return;
}
Object firstElement = ss.getFirstElement();
if ( firstElement == null )
{
setRestrictedEnabled( false );
return;
}
if ( firstElement instanceof PropertySheetEntry )
{
PropertySheetEntry entry = (PropertySheetEntry) firstElement;
if ( entry.getEditor( parent ) == null )
{
setRestrictedEnabled( false );
return;
}
}
}
setRestrictedEnabled( true );
}
@Override
public void selectionChanged( final IWorkbenchPart part,
final ISelection selection )
{
super.selectionChanged( part, selection );
if ( !( selection instanceof IStructuredSelection ) )
{
containerSelection = null;
return;
}
IStructuredSelection parSs = (IStructuredSelection) selection;
if ( parSs.isEmpty() )
{
containerSelection = null;
refresh();
return;
}
Object parFirstElement = parSs.getFirstElement();
if ( !( parFirstElement instanceof PropertyContainer ) )
{
containerSelection = null;
return;
}
containerSelection = (PropertyContainer) parFirstElement;
}
@Override
public void setPropertySourceProvider(
final IPropertySourceProvider newProvider )
{
super.setPropertySourceProvider( newProvider );
}
}