/*******************************************************************************
 * Copyright (c) 2004 Actuate Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.report.designer.ui.views.attributes;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.eclipse.birt.report.designer.core.model.SessionHandleAdapter;
import org.eclipse.birt.report.designer.core.util.mediator.IColleague;
import org.eclipse.birt.report.designer.core.util.mediator.request.ReportRequest;
import org.eclipse.birt.report.designer.internal.ui.editors.schematic.editparts.DummyEditpart;
import org.eclipse.birt.report.designer.internal.ui.editors.schematic.editparts.ReportElementEditPart;
import org.eclipse.birt.report.designer.internal.ui.util.ExceptionHandler;
import org.eclipse.birt.report.designer.internal.ui.util.UIUtil;
import org.eclipse.birt.report.designer.internal.ui.views.actions.GlobalActionFactory;
import org.eclipse.birt.report.designer.nls.Messages;
import org.eclipse.birt.report.designer.ui.IReportGraphicConstants;
import org.eclipse.birt.report.designer.ui.ReportPlatformUIImages;
import org.eclipse.birt.report.designer.ui.ReportPlugin;
import org.eclipse.birt.report.designer.util.DEUtil;
import org.eclipse.birt.report.model.api.DesignElementHandle;
import org.eclipse.birt.report.model.api.GroupElementHandle;
import org.eclipse.birt.report.model.api.activity.SemanticException;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.ui.INullSelectionListener;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.part.ViewPart;

/**
 * Attribute view shows the attributes of the selected control. If no control is
 * selected, it will show no attributes and a sentence describing there is
 * nothing to show for the selected object.
 * </p>
 * Multi-selection of control of the same type will normally show the same UI as
 * if only one control was selected. Some of the values may be gray or blank if
 * the selected controls have different attributes. If the controls have
 * different type, nothing will be shown in the attributes view.
 * </P>
 */
public class AttributeView extends ViewPart implements
		INullSelectionListener,
		IColleague
{

	/**
	 * AttributeView ID
	 */
	public static final String ID = "org.eclipse.birt.report.designer.ui.attributes.AttributeView";//$NON-NLS-1$

	/**
	 * WorkbenchPart ID list that attribute view interests in selection changing
	 * occupied in these WorkbenchParts.
	 */
	protected List PART_IDS = Arrays.asList( new String[]{
			"org.eclipse.birt.report.designer.ui.editors.ReportEditor",//$NON-NLS-1$
			"org.eclipse.birt.report.designer.ui.editors.LibraryReportEditor",//$NON-NLS-1$
			"org.eclipse.birt.report.designer.ui.editors.TemplateEditor",//$NON-NLS-1$
			IPageLayout.ID_OUTLINE,
	} );

	/**
	 * TabFolder component contains Tab pages. After selection changed, the
	 * TabFolder will reset its content.
	 */
	protected TabFolder tabFolder;

	/**
	 * Keeps current selection When AttributeView is not on the top of window.
	 */
	private ISelection selection;

	/**
	 * Attribute view UI builder
	 */
	private AttributesBuilder builder;

	/**
	 * IPartListener to track the close event of graphical editor.
	 */
	private IPartListener partListener;

	// fields to remember the last selected tab (sticky behaviour)
	private int tabIndex = 0;
	private String tabText;

	// add restore library properties action
	private RestoreLibraryPropertiesAction restoreLibraryPropertiesAction;

	public class RestoreLibraryPropertiesAction extends Action
	{

		AttributeView view;

		RestoreLibraryPropertiesAction( AttributeView view )
		{
			this.view = view;
			setImageDescriptor( ReportPlatformUIImages.getImageDescriptor( IReportGraphicConstants.ICON_ENABLE_RESTORE_PROPERTIES ) );
			setEnabled( false );
			setToolTipText( Messages.getString( "AttributeView.toolbar.tooltip.RestoreLibraryPropertiesAction.RestoreMsg" ) );
		}

		public void run( )
		{
			if ( view != null )
			{

				MessageDialog prefDialog = new MessageDialog( UIUtil.getDefaultShell( ),
						Messages.getString( "AttributeView.dialg.Message.Warning" ),//$NON-NLS-1$
						null,
						Messages.getString( "AttributeView.dialg.Message.PromptMsg" ),//$NON-NLS-1$
						MessageDialog.INFORMATION,
						new String[]{
								Messages.getString( "AttributeView.dialg.Message.Yes" ),//$NON-NLS-1$
								Messages.getString( "AttributeView.dialg.Message.No" ),//$NON-NLS-1$
								Messages.getString( "AttributeView.dialg.Message.Cancel" )}, 0 );//$NON-NLS-1$
				int ret = prefDialog.open( );

				if ( !( ret == 2 ) )
				{

					if ( ret == Window.OK )
					{
						resetLocalProperties( ret );
						showPropertiesPage( );
						setEnabled( false );
					}
				}

			}
		}
	}

	// selection listener to detect when user is switching tabs
	private SelectionListener selectionListener = new SelectionAdapter( ) {

		public void widgetSelected( SelectionEvent e )
		{
			// when the item selection is changing in the editor,
			// a selection event is fired for the first created tabItem
			// we ignore it (changingSelection=true)
			// otherwise, the user is switching tabs, we remember the tabIndex,
			// and text
			if ( tabFolder != null && !changingSelection )
			{
				tabIndex = tabFolder.getSelectionIndex( );
				if ( tabFolder.getSelection( ).length > 0 )
				{
					tabText = tabFolder.getSelection( )[0].getText( );
				}
			}
		}
	};

	// boolean to indicate the ui editor selection is changing and that
	// new tabs are being created for the new selected element
	private boolean changingSelection = false;

	/**
	 * Return the selectionListener
	 * 
	 * @return
	 */
	public SelectionListener getSelectionListener( )
	{
		return selectionListener;
	}

	/**
	 * Clear all the local properties
	 * 
	 * @param ret
	 */
	public void resetLocalProperties( int ret )
	{
		try
		{
			DEUtil.getGroupElementHandle( getModelList( new StructuredSelection( SessionHandleAdapter.getInstance( )
					.getMediator( )
					.getCurrentState( )
					.getSelectionObject( ) ) ) )
					.clearLocalProperties( );
		}
		catch ( SemanticException e )
		{
			ExceptionHandler.handle( e );
		}
		return;
	}

	/**
	 * Creates the SWT controls for this workbench part.
	 * <p>
	 * Clients should not call this method (the workbench calls this method when
	 * it needs to, which may be never).
	 * </p>
	 * <p>
	 * For implementors this is a multi-step process:
	 * <ol>
	 * <li>Create one or more controls within the parent.</li>
	 * <li>Set the parent layout as needed.</li>
	 * <li>Register any global actions with the <code>IActionService</code>.
	 * </li>
	 * <li>Register any popup menus with the <code>IActionService</code>.
	 * </li>
	 * <li>Register a selection provider with the
	 * <code>ISelectionService</code> (optional).</li>
	 * </ol>
	 * </p>
	 * 
	 * @param parent
	 *            the parent control
	 */
	public void createPartControl( Composite parent )
	{
		addActions( );

		tabFolder = new TabFolder( parent, SWT.TOP );
		tabFolder.addSelectionListener( selectionListener );

		builder = new AttributesBuilder( );
		partListener = new IPartListener( ) {

			public void partActivated( IWorkbenchPart part )
			{
			}

			public void partBroughtToTop( IWorkbenchPart part )
			{
			}

			public void partClosed( IWorkbenchPart part )
			{
				if ( part != null
						&& PART_IDS.contains( part.getSite( ).getId( ) ) )
					resetTabFolder( null );
			}

			public void partDeactivated( IWorkbenchPart part )
			{
				if ( part != null && ID.equals( part.getSite( ).getId( ) ) )
				{
					Control control = Display.getCurrent( ).getFocusControl( );
					if ( control != null )
						control.notifyListeners( SWT.FocusOut, null );
				}
			}

			public void partOpened( IWorkbenchPart part )
			{
			}
		};

		IWorkbenchPage page = getSite( ).getPage( );
		page.addSelectionListener( this );
		page.addPartListener( partListener );
		selection = page.getSelection( );

		// suport the mediator
		SessionHandleAdapter.getInstance( )
				.getMediator( )
				.addGlobalColleague( this );
	}

	private void addActions( )
	{
		if ( restoreLibraryPropertiesAction == null )
		{
			restoreLibraryPropertiesAction = new RestoreLibraryPropertiesAction( this );
		}

		getViewSite( ).getActionBars( )
				.getToolBarManager( )
				.add( restoreLibraryPropertiesAction );

		// getViewSite( ).getActionBars( ).getToolBarManager( ).add(
		// enableEditingToggleAction );

		// GroupElementHandle handle = DEUtil.getGroupElementHandle(
		// getModelList( new StructuredSelection(
		// SessionHandleAdapter.getInstance( )
		// .getMediator( )
		// .getCurrentState( )
		// .getSelectionObject( ) ) ) );
		// if ( handle != null )
		// {
		// enableEditingToggleAction.setEnabled( handle.isExtendedElements( ) );
		// }
		//
		// changeToolTip( );

	}

	/*
	 * shows the attributes of the selected control
	 */
	private void showPropertiesPage( )
	{
		if ( SessionHandleAdapter.getInstance( ).getReportDesignHandle( ) != null )
		{
			handleGlobalAction( );
			builder.createPages( tabFolder,
					getModelList( new StructuredSelection( SessionHandleAdapter.getInstance( )
							.getMediator( )
							.getCurrentState( )
							.getSelectionObject( ) ) ) );
			selectStickyTab( );
			setPartName( builder.getTypeInfo( ) );
		}
	}

	/**
	 * Asks this part to take focus within the workbench.
	 * <p>
	 * Clients should not call this method (the workbench calls this method at
	 * appropriate times). To have the workbench activate a part, use
	 * <code>IWorkbenchPage.activate(IWorkbenchPart) instead</code>.
	 * </p>
	 */
	public void setFocus( )
	{
		tabFolder.setFocus( );
		if ( selection != null )
		{
			showPropertiesPage( );
			selection = null;
		}
	}

	/**
	 * After selection changed, the attribute Tab Pages will re-compute to show
	 * attributes of the selection.
	 * 
	 * @param selection
	 *            The current selection.
	 */
	private void resetTabFolder( ISelection selection )
	{
		if ( tabFolder == null || tabFolder.isDisposed( ) )
			return;

		if ( SessionHandleAdapter.getInstance( ).getReportDesignHandle( ) != null )
		{
			handleGlobalAction( );
			builder.createPages( tabFolder, getModelList( selection ) );
			selectStickyTab( );
		}

		setPartName( builder.getTypeInfo( ) );
	}

	private boolean hasLocalProperties( ISelection selection )
	{
		GroupElementHandle groupHandle = DEUtil.getGroupElementHandle( getModelList( selection ) );

		return groupHandle.hasLocalPropertiesForExtendedElements( );
	}

	/**
	 * Sticky tab behaviour. We try to set the default selection on the previous
	 * chosen tab by the user or the nearest one.
	 */
	private void selectStickyTab( )
	{
		TabItem[] items = tabFolder.getItems( );
		boolean tabFound = false;
		for ( int i = 0; i < items.length; i++ )
		{
			if ( items[i].getText( ).equals( tabText ) )
			{
				tabFolder.setSelection( i );
				tabFound = true;
				break;
			}
		}
		// we didn't find the tab, select the one with the closest tabIndex
		// instead
		if ( !tabFound )
		{
			if ( tabIndex > tabFolder.getItemCount( ) - 1 )
			{
				tabFolder.setSelection( tabFolder.getItemCount( ) - 1 );
			}
			else
			{
				tabFolder.setSelection( tabIndex );
			}
		}
	}

	/**
	 * Parse out the DE models for all kinds of input source.
	 * 
	 * @param selection
	 *            the current selection.
	 * @return
	 */
	private List getModelList( ISelection selection )
	{
		List list = new ArrayList( );
		if ( selection == null )
			return list;
		if ( !( selection instanceof StructuredSelection ) )
			return list;

		StructuredSelection structured = (StructuredSelection) selection;
		if ( structured.getFirstElement( ) instanceof ReportElementEditPart )
		{
			boolean bool = false;
			for ( Iterator it = structured.iterator( ); it.hasNext( ); )
			{
				ReportElementEditPart object = (ReportElementEditPart) it.next( );
				if ( object instanceof DummyEditpart )
				{
					list.add( object.getModel( ) );
					bool = true;
				}
				if ( !bool )
				{
					list.add( object.getModel( ) );
				}
			}
		}
		else
		{
			list = structured.toList( );
		}
		return list;
	}

	/**
	 * Notifies this listener that the selection has changed.
	 * <p>
	 * This method is called when the selection changes from one to a
	 * <code>non-null</code> value, but not when the selection changes to
	 * <code>null</code>. If there is a requirement to be notified in the
	 * latter scenario, implement <code>INullSelectionListener</code>. The
	 * event will be posted through this method.
	 * </p>
	 * 
	 * @param part
	 *            the workbench part containing the selection
	 * @param selection
	 *            the current selection. This may be <code>null</code> if
	 *            <code>INullSelectionListener</code> is implemented.
	 */
	public void selectionChanged( IWorkbenchPart part, ISelection selection )
	{
		// if ( part != null && !PART_IDS.contains( part.getSite( ).getId( ) )
		// && !ID.equals( part.getSite( ).getId( ) )
		// && !PaletteView.ID.equals( part.getSite( ).getId( ) ) )
		if ( SessionHandleAdapter.getInstance( ).getReportDesignHandle( ) != null )
		{
			if ( part != null
					&& !ReportPlugin.getDefault( )
							.containIgnoreViewID( part.getSite( ).getId( ) ) )
			{
				selection = new StructuredSelection( );
				handleSelectionChanged( selection );
			}
		}
	}

	/**
	 * Disposes of this workbench part.
	 * <p>
	 * This is the last method called on the <code>IWorkbenchPart</code>. At
	 * this point the part controls (if they were ever created) have been
	 * disposed as part of an SWT composite. There is no guarantee that
	 * createPartControl() has been called, so the part controls may never have
	 * been created.
	 * </p>
	 * <p>
	 * Within this method a part may release any resources, fonts, images,
	 * etc.&nbsp; held by this part. It is also very important to deregister all
	 * listeners from the workbench.
	 * </p>
	 * <p>
	 * Clients should not call this method (the workbench calls this method at
	 * appropriate times).
	 * </p>
	 */
	public void dispose( )
	{
		IWorkbenchPage page = getSite( ).getPage( );
		page.removeSelectionListener( this );
		page.removePartListener( partListener );

		// remove the mediator listener
		SessionHandleAdapter.getInstance( )
				.getMediator( )
				.removeGlobalColleague( this );
		super.dispose( );
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.IViewPart#init(org.eclipse.ui.IViewSite)
	 */
	public void init( IViewSite site ) throws PartInitException
	{
		site.setSelectionProvider( new ISelectionProvider( ) {

			public void addSelectionChangedListener(
					ISelectionChangedListener listener )
			{
			}

			public ISelection getSelection( )
			{
				return null;
			}

			public void removeSelectionChangedListener(
					ISelectionChangedListener listener )
			{
			}

			public void setSelection( ISelection selection )
			{
			}
		} );
		super.init( site );
	}

	/**
	 * Handles all global actions
	 */
	private void handleGlobalAction( )
	{
		for ( int i = 0; i < GlobalActionFactory.GLOBAL_STACK_ACTIONS.length; i++ )
		{
			String id = GlobalActionFactory.GLOBAL_STACK_ACTIONS[i];
			getViewSite( ).getActionBars( ).setGlobalActionHandler( id,
					GlobalActionFactory.createStackAction( id,
							SessionHandleAdapter.getInstance( )
									.getCommandStack( ) ) );
		}
		
		getViewSite( ).getActionBars( ).setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(),
	                new SelectAllAction());
	}

	private static class SelectAllAction extends Action
	{
		private SelectAllAction()
		{
			setId(ActionFactory.SELECT_ALL.getId()  );
		}
		public void runWithEvent( Event event )
		{
			try
			{
				execute();
			}
			catch ( ExecutionException e )
			{
				ExceptionHandler.handle( e );
			}
		}
		/**
		 * The parameters to pass to the method this handler invokes. This handler
		 * always passes no parameters.
		 */
		protected static final Class[] NO_PARAMETERS = new Class[0];
		
		private static final String methodName = "selectAll";//$NON-NLS-1$

		public final Object execute()
				throws ExecutionException 
		{
			final Method methodToExecute = getMethodToExecute();
			if (methodToExecute != null) {
				try {
					final Control focusControl = Display.getCurrent()
							.getFocusControl();
					
					// if it's an embedded swing component, fail gracefully for now.
					if ((focusControl instanceof Composite)
	                        && ((((Composite) focusControl).getStyle() & SWT.EMBEDDED) != 0)) {
						return null;
					}
					
					final int numParams = methodToExecute.getParameterTypes().length;

					if (numParams == 0) {
						// This is a no-argument selectAll method.
						methodToExecute.invoke(focusControl, null);
						focusControl.notifyListeners(SWT.Selection, null);

					} else if (numParams == 1) {
						// This is a single-point selection method.
						final Method textLimitAccessor = focusControl.getClass()
								.getMethod("getTextLimit", NO_PARAMETERS); //$NON-NLS-1$
						final Integer textLimit = (Integer) textLimitAccessor
								.invoke(focusControl, null);
						final Object[] parameters = { new Point(0, textLimit
								.intValue()) };
						methodToExecute.invoke(focusControl, parameters);
						focusControl.notifyListeners(SWT.Selection, null);

					} else {
						/*
						 * This means that getMethodToExecute() has been changed,
						 * while this method hasn't.
						 */
						throw new ExecutionException(
								"Too many parameters on select all", new Exception()); //$NON-NLS-1$

					}

				} catch (IllegalAccessException e) {
					// The method is protected, so do nothing.

				} catch (InvocationTargetException e) {
					throw new ExecutionException(
							"An exception occurred while executing " //$NON-NLS-1$
									+ getMethodToExecute(), e.getTargetException());

				} catch (NoSuchMethodException e) {
					// I can't get the text limit. Do nothing.

				}
			}

			return null;
		}

		/**
		 * Looks up the select all method on the given focus control.
		 * 
		 * @return The method on the focus control; <code>null</code> if none.
		 */
		protected Method getMethodToExecute() {
			final Control focusControl = Display.getCurrent().getFocusControl();
			Method method = null;

			if (focusControl != null) {
				final Class clazz = focusControl.getClass();
				try {
					method = clazz.getMethod(methodName, NO_PARAMETERS);
				} catch (NoSuchMethodException e) {
					// Fall through...
				}
			}

			if ((method == null)
					&& (focusControl instanceof Composite)
					&& ((((Composite) focusControl).getStyle() & SWT.EMBEDDED) != 0)) {
				/*
				 * We couldn't find the appropriate method on the current focus
				 * control. It is possible that the current focus control is an
				 * embedded SWT composite, which could be containing some Swing
				 * components. If this is the case, then we should try to pass
				 * through to the underlying Swing component hierarchy. Insha'allah,
				 * this will work.
				 */
	            try {
	                final Class focusManagerClass = Class
	                        .forName("javax.swing.FocusManager"); //$NON-NLS-1$
	                final Method focusManagerGetCurrentManagerMethod = focusManagerClass
	                        .getMethod("getCurrentManager", null); //$NON-NLS-1$
	                final Object focusManager = focusManagerGetCurrentManagerMethod
	                        .invoke(focusManagerClass, null);
	                final Method focusManagerGetFocusOwner = focusManagerClass
	                        .getMethod("getFocusOwner", null); //$NON-NLS-1$
	                final Object focusComponent = focusManagerGetFocusOwner.invoke(
	                        focusManager, null);
	                final Class clazz = focusComponent.getClass();

	                try {
	                    method = clazz.getMethod(methodName, NO_PARAMETERS);
	                } catch (NoSuchMethodException e) {
	                    // Do nothing.
	                }
	            } catch (final ClassNotFoundException e) {
	                // There is no Swing support, so do nothing.

	            } catch (final NoSuchMethodException e) {
	                // The API has changed, which seems amazingly unlikely.
	                throw new Error("Something is seriously wrong here"); //$NON-NLS-1$
	            } catch (IllegalAccessException e) {
	                // The API has changed, which seems amazingly unlikely.
	                throw new Error("Something is seriously wrong here"); //$NON-NLS-1$
	            } catch (InvocationTargetException e) {
	                // The API has changed, which seems amazingly unlikely.
	                throw new Error("Something is seriously wrong here"); //$NON-NLS-1$
	            }
	        }

			return method;
		}
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.birt.report.designer.core.util.mediator.IColleague#performRequest(org.eclipse.birt.report.designer.core.util.mediator.request.ReportRequest)
	 */
	public void performRequest( ReportRequest request )
	{
		if ( ReportRequest.SELECTION.equals( request.getType( ) ) )
		{
			handleSelectionChanged( new StructuredSelection( request.getSelectionModelList( ) ) );
		}
	}

	/**
	 * Notifies this listener that the selection has changed.
	 * <p>
	 * This method is called when the selection changes from one to a
	 * <code>non-null</code> value, but not when the selection changes to
	 * <code>null</code>. If there is a requirement to be notified in the
	 * latter scenario, implement <code>INullSelectionListener</code>. The
	 * event will be posted through this method.
	 * </p>
	 * 
	 * @param part
	 *            the workbench part containing the selection
	 * @param selection
	 *            the current selection. This may be <code>null</code> if
	 *            <code>INullSelectionListener</code> is implemented.
	 */
	public void handleSelectionChanged( ISelection selection )
	{
		this.selection = null;

		if ( !tabFolder.isVisible( ) )
		{
			this.selection = selection;
			return;
		}
		// changingSelection = true;
		// resetTabFolder( selection );

		restoreLibraryPropertiesAction.setEnabled( hasLocalProperties( selection ) );
		// enableEditingToggleAction.setEnabled(
		// DEUtil.getGroupElementHandle(
		// getModelList( selection ) ).isExtendedElements( ) );
		// changeToolTip( );
		// changingSelection = false;
		showPropertiesPage( );
	}

	static class MessagePageGenerator extends DefaultPageGenerator
	{

		public void createTabItems( TabFolder tabFolder, List input )
		{
			super.createTabItems( tabFolder, input );
			Composite pane = new Composite( tabFolder, SWT.NONE );
			pane.setLayout( new FillLayout( ) );

			new MessageAttributePage( pane, SWT.NONE, input );

			TabItem tabItem = new TabItem( tabFolder, SWT.NONE );

			if ( input.get( 0 ) instanceof ModelClassWrapper )
			{
				tabItem.setText( ( (ModelClassWrapper) input.get( 0 ) ).getTypeMessage( ) );
			}
			tabItem.setControl( pane );
		}
	}

	static class MessageAttributePage extends Composite
	{

		private List model;

		public MessageAttributePage( Composite parent, int style, List input )
		{
			super( parent, style );
			model = input;
			buildUI( );

		}

		private void buildUI( )
		{

			FillLayout layout = new FillLayout( );
			setLayout( layout );

			Label label = new Label( this, SWT.LEFT | SWT.TOP | SWT.WRAP );
			String extendsString = "";//$NON-NLS-1$
			if ( model.get( 0 ) instanceof ModelClassWrapper )
			{

				extendsString = ( (ModelClassWrapper) model.get( 0 ) ).getExtendsString( );
			}

			label.setText( extendsString );
		}
	}

	static class ModelClassWrapper
	{

		private GroupElementHandle groupElementHandle;

		public ModelClassWrapper( List modelList )
		{
			groupElementHandle = DEUtil.getMultiSelectionHandle( modelList );
		}

		public String getTypeMessage( )
		{
			if ( groupElementHandle.getElements( ).get( 0 ) instanceof DesignElementHandle )
			{
				return DEUtil.getDisplayLabel( ( (DesignElementHandle) groupElementHandle.getElements( )
						.get( 0 ) ) );
			}
			return "";//$NON-NLS-1$
		}

		public String getExtendsString( )
		{
			DesignElementHandle handle = (DesignElementHandle) groupElementHandle.getElements( )
					.get( 0 );
			String name = DEUtil.getDisplayLabel( handle );
			String extendsFrom = handle.getExtends( ).getDisplayLabel( );
			String libName = handle.getExtends( ).getRoot( ).getDisplayLabel( );
			return Messages.getFormattedString( "AttributeView.view.message.Emptypage", new Object[]{name,//$NON-NLS-1$
							extendsFrom,
							libName,
							name
					} );
		}

		public Object getElement( )
		{
			if ( groupElementHandle != null )
			{
				return groupElementHandle.getElements( ).get( 0 );
			}
			return new Object( );
		}
	}
}
