| /******************************************************************************* |
| * Copyright (c) 2004, 2005 Sybase, Inc. and others. |
| * |
| * 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: |
| * Sybase, Inc. - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.jst.jsf.facesconfig.ui; |
| |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.core.runtime.SafeRunner; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.util.SafeRunnable; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.ISelectionProvider; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jst.jsf.common.ui.internal.logging.Logger; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.CTabFolder; |
| import org.eclipse.swt.custom.CTabItem; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.ui.IActionBars; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.SubActionBars; |
| import org.eclipse.ui.part.EditorPart; |
| import org.eclipse.ui.part.IPage; |
| import org.eclipse.ui.part.IPageBookViewPage; |
| import org.eclipse.ui.part.IPageSite; |
| import org.eclipse.ui.part.MessagePage; |
| import org.eclipse.ui.part.MultiPageEditorPart; |
| import org.eclipse.ui.part.Page; |
| import org.eclipse.ui.part.PageBook; |
| import org.eclipse.ui.views.contentoutline.IContentOutlinePage; |
| |
| /** |
| * @author Xiao-guang Zhang |
| * |
| * The outline page class for mulitPage Editorpart. |
| */ |
| public class MultiPageEditorOutlinePage extends Page implements |
| IContentOutlinePage, SelectionListener { |
| /** log instance */ |
| private static final Logger log = EditorPlugin |
| .getLogger(MultiPageEditorOutlinePage.class); |
| |
| /** |
| * Selection change listeners. |
| */ |
| private ListenerList selectionChangedListeners = new ListenerList(ListenerList.IDENTITY); |
| |
| /** the pagebook */ |
| private PageBook pageBook = null; |
| |
| /** |
| * Selection change listener to listen for page selection changes |
| */ |
| private ISelectionChangedListener selectionChangedListener = new ISelectionChangedListener() { |
| public void selectionChanged(SelectionChangedEvent event) { |
| pageSelectionChanged(event); |
| } |
| }; |
| |
| /** |
| * A data structure used to store the information about a single page within |
| * a MultiPageEditorOutlinePage |
| */ |
| protected static class PageRec { |
| |
| /** |
| * The part including editorpart, or Control |
| */ |
| public IWorkbenchPart part; |
| |
| /** |
| * The page. |
| */ |
| public IPage page; |
| |
| /** |
| * The page's action bars |
| */ |
| public SubActionBars subActionBars; |
| |
| /** |
| * Creates a new page record initialized to the given part and page. |
| * |
| * @param part |
| * @param page |
| */ |
| public PageRec(IWorkbenchPart part, IPage page) { |
| this.part = part; |
| this.page = page; |
| } |
| |
| /** |
| * Disposes of this page record by <code>null</code>ing its fields. |
| */ |
| public void dispose() { |
| part = null; |
| page = null; |
| } |
| } |
| |
| /** |
| * The page record for the default page. |
| */ |
| private PageRec defaultPageRec; |
| |
| /** |
| * Map from parts to part records (key type: <code>IWorkbenchPart</code>; |
| * value type: <code>PartRec</code>). |
| */ |
| private Map mapPartToRec = new HashMap(); |
| |
| /** |
| * Map from pages to view sites Note that view sites were not added to page |
| * recs to avoid breaking binary compatibility with previous builds |
| */ |
| private Map mapPageToSite = new HashMap(); |
| |
| /** |
| * The page rec which provided the current page or <code>null</code> |
| */ |
| private PageRec activeRec; |
| |
| /** |
| * the container composite control of MutliPageEditorPart |
| */ |
| private CTabFolder tabFolder; |
| |
| /** |
| * Creates a new MultiPageEditorOutlinePage instance. |
| * |
| * |
| */ |
| public MultiPageEditorOutlinePage() { |
| super(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.part.Page#createControl(org.eclipse.swt.widgets.Composite) |
| */ |
| public void createControl(Composite parent) { |
| // pagebook |
| pageBook = new PageBook(parent, SWT.NONE); |
| |
| // Create the default page rec. |
| IPage defaultPage = createDefaultPage(pageBook); |
| defaultPageRec = new PageRec(null, defaultPage); |
| preparePage(defaultPageRec); |
| |
| // Show the default page |
| showPageRec(defaultPageRec); |
| |
| // get the tab control and add the page selection listener. |
| if (getContainerForMultiPageEditorPart() != null) { |
| getContainerForMultiPageEditorPart().addSelectionListener(this); |
| } |
| |
| // show the activate part page. |
| showBootstrapPart(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see Page#dispose() |
| */ |
| public void dispose() { |
| // Deref all of the pages. |
| activeRec = null; |
| if (defaultPageRec != null) { |
| // check for null since the default page may not have |
| // been created (ex. perspective never visible) |
| defaultPageRec.page.dispose(); |
| defaultPageRec = null; |
| } |
| Map clone = (Map) ((HashMap) mapPartToRec).clone(); |
| Iterator iterator = clone.values().iterator(); |
| while (iterator.hasNext()) { |
| PageRec rec = (PageRec) iterator.next(); |
| removePage(rec); |
| } |
| |
| // important: always call super implementation of dispose |
| super.dispose(); |
| } |
| |
| /** |
| * Creates and returns the default page for this view. |
| * |
| * @param book - |
| * the pagebook control |
| * @return - the default page |
| */ |
| protected IPage createDefaultPage(PageBook book) { |
| // Message to show on the default page |
| String defaultText = EditorMessages.MultiPageEditorOutlinePage_noOutline; |
| |
| MessagePage page = new MessagePage(); |
| initPage(page); |
| page.createControl(book); |
| page.setMessage(defaultText); |
| return page; |
| } |
| |
| /** |
| * Prepares the page in the given page rec for use in this view. |
| * |
| * @param rec - |
| * the page rec |
| */ |
| private void preparePage(PageRec rec) { |
| IPageSite site = null; |
| |
| if (!doesPageExist(rec.page)) { |
| if (rec.page instanceof IPageBookViewPage) { |
| site = ((IPageBookViewPage) rec.page).getSite(); |
| } |
| if (site == null) { |
| // We will create a site for our use |
| site = new SubPageSite(getSite()); |
| } |
| mapPageToSite.put(rec.page, site); |
| |
| rec.subActionBars = (SubActionBars) site.getActionBars(); |
| // rec.subActionBars.addPropertyChangeListener(actionBarPropListener); |
| // for backward compability with IPage |
| rec.page.setActionBars(rec.subActionBars); |
| |
| } else { |
| site = (IPageSite) mapPageToSite.get(rec.page); |
| rec.subActionBars = (SubActionBars) site.getActionBars(); |
| } |
| } |
| |
| /** |
| * Returns the currently visible page for this view or <code>null</code> |
| * if no page is currently visible. |
| * |
| * @return the currently visible page |
| */ |
| public IPage getCurrentPage() { |
| if (activeRec == null) |
| return null; |
| return activeRec.page; |
| } |
| |
| /** |
| * Returns the view site for the given page of this view. |
| * |
| * @param page |
| * the page |
| * @return the corresponding site, or <code>null</code> if not found |
| */ |
| protected SubPageSite getPageSite(IPage page) { |
| return (SubPageSite) mapPageToSite.get(page); |
| } |
| |
| /** |
| * Shows page contained in the given page record in this view. The page |
| * record must be one from this pagebook view. |
| * <p> |
| * The <code>PageBookView</code> implementation of this method asks the |
| * pagebook control to show the given page's control, and records that the |
| * given page is now current. Subclasses may extend. |
| * </p> |
| * |
| * @param pageRec |
| * the page record containing the page to show |
| */ |
| protected void showPageRec(PageRec pageRec) { |
| IPageSite pageSite = getPageSite(pageRec.page); |
| ISelectionProvider provider = pageSite.getSelectionProvider(); |
| if (provider == null && (pageRec.page instanceof IContentOutlinePage)) { |
| // This means that the page did not set a provider during its |
| // initialization |
| // so for backward compatibility we will set the page itself as the |
| // provider. |
| pageSite.setSelectionProvider((IContentOutlinePage) pageRec.page); |
| } |
| |
| // If already showing do nothing |
| if (activeRec == pageRec) { |
| return; |
| } |
| // If the page is the same, just set activeRec to pageRec |
| if (activeRec != null && pageRec != null |
| && activeRec.page == pageRec.page) { |
| activeRec = pageRec; |
| return; |
| } |
| |
| // Hide old page. |
| if (activeRec != null) { |
| activeRec.subActionBars.deactivate(); |
| // remove our selection listener |
| provider = ((SubPageSite) mapPageToSite.get(activeRec.page)) |
| .getSelectionProvider(); |
| if (provider != null) { |
| provider |
| .removeSelectionChangedListener(selectionChangedListener); |
| } |
| } |
| // Show new page. |
| activeRec = pageRec; |
| Control pageControl = activeRec.page.getControl(); |
| if (pageControl != null && !pageControl.isDisposed()) { |
| // Verify that the page control is not disposed |
| // If we are closing, it may have already been disposed |
| pageBook.showPage(pageControl); |
| activeRec.subActionBars.activate(); |
| refreshGlobalActionHandlers(); |
| // add our selection listener |
| provider = ((SubPageSite) mapPageToSite.get(activeRec.page)) |
| .getSelectionProvider(); |
| if (provider != null) { |
| provider.addSelectionChangedListener(selectionChangedListener); |
| } |
| // Update action bars. |
| getSite().getActionBars().updateActionBars(); |
| } |
| } |
| |
| /** |
| * Refreshes the global actions for the active page. |
| */ |
| private void refreshGlobalActionHandlers() { |
| // Clear old actions. |
| IActionBars bars = getSite().getActionBars(); |
| bars.clearGlobalActionHandlers(); |
| |
| // Set new actions. |
| Map newActionHandlers = activeRec.subActionBars |
| .getGlobalActionHandlers(); |
| if (newActionHandlers != null) { |
| Set keys = newActionHandlers.entrySet(); |
| Iterator iter = keys.iterator(); |
| while (iter.hasNext()) { |
| Map.Entry entry = (Map.Entry) iter.next(); |
| bars.setGlobalActionHandler((String) entry.getKey(), |
| (IAction) entry.getValue()); |
| } |
| } |
| } |
| |
| /** |
| * Creates a page for a given part. Adds it to the pagebook but does not |
| * show it. |
| * |
| * @param part |
| * The part we are making a page for. |
| * @return IWorkbenchPart |
| */ |
| private PageRec createPage(IWorkbenchPart part) { |
| PageRec rec = doCreatePage(part); |
| if (rec != null) { |
| mapPartToRec.put(part, rec); |
| preparePage(rec); |
| } |
| return rec; |
| } |
| |
| /* |
| * (non-Javadoc) Method declared on PageBookView. |
| */ |
| private PageRec doCreatePage(IWorkbenchPart part) { |
| // Try to get an outline page. |
| Object obj = part.getAdapter(IContentOutlinePage.class); |
| if (obj instanceof IContentOutlinePage) { |
| IContentOutlinePage page = (IContentOutlinePage) obj; |
| if (page instanceof IPageBookViewPage) { |
| initPage((IPageBookViewPage) page); |
| } |
| page.createControl(getPageBook()); |
| return new PageRec(part, page); |
| } |
| // There is no content outline |
| return null; |
| } |
| |
| /** |
| * Returns the pagebook control for this view. |
| * |
| * @return the pagebook control, or <code>null</code> if not initialized |
| */ |
| protected PageBook getPageBook() { |
| return pageBook; |
| } |
| |
| /** |
| * Returns the page record for the given part. |
| * |
| * @param part |
| * the part |
| * @return the corresponding page record, or <code>null</code> if not |
| * found |
| */ |
| protected PageRec getPageRec(Object part) { |
| return (PageRec) mapPartToRec.get(part); |
| } |
| |
| /** |
| * Initializes the given page with a page site. |
| * <p> |
| * Subclasses should call this method after the page is created but before |
| * creating its controls. |
| * </p> |
| * <p> |
| * Subclasses may override |
| * </p> |
| * |
| * @param page |
| * The page to initialize |
| */ |
| protected void initPage(IPageBookViewPage page) { |
| try { |
| page.init(new SubPageSite(getSite())); |
| } catch (PartInitException e) { |
| log.error(e.getMessage()); |
| } |
| } |
| |
| /** |
| * Shows a page for the active workbench part. |
| */ |
| private void showBootstrapPart() { |
| IWorkbenchPart part = getBootstrapPart(); |
| if (part != null) { |
| partActivated(part); |
| } |
| } |
| |
| /** |
| * Returns the active, important workbench part for this view. |
| * |
| * @return the active important part, or <code>null</code> if none |
| */ |
| private IWorkbenchPart getBootstrapPart() { |
| IWorkbenchPage page = getSite().getPage(); |
| if (page != null |
| && page.getActiveEditor() instanceof MultiPageEditorPart) { |
| // get active editor of mutli-page editor. |
| return (IWorkbenchPart) page.getActiveEditor().getAdapter( |
| IEditorPart.class); |
| } |
| return null; |
| } |
| |
| /** |
| * This method shows the page when the given part is activated. Subclasses |
| * may extend. |
| */ |
| private void partActivated(IWorkbenchPart part) { |
| // Is this an important part? If not just return. |
| if (!isImportant(part)) { |
| return; |
| } |
| |
| // Create a page for the part. |
| PageRec rec = getPageRec(part); |
| if (rec == null) { |
| rec = createPage(part); |
| } |
| |
| // Show the page. |
| if (rec != null) { |
| showPageRec(rec); |
| } else { |
| showPageRec(defaultPageRec); |
| } |
| } |
| |
| /** |
| * Returns true if the page has already been created. |
| * |
| * @param page |
| * the page to test |
| * @return true if this page has already been created. |
| */ |
| private boolean doesPageExist(IPage page) { |
| return mapPageToSite.containsKey(page); |
| } |
| |
| /** |
| * Returns whether the given part should be added to this view. |
| * |
| * @param part |
| * the input part |
| * @return <code>true</code> if the part is relevant, and |
| * <code>false</code> otherwise |
| */ |
| protected boolean isImportant(IWorkbenchPart part) { |
| // We only care about editors |
| return (part instanceof IEditorPart); |
| } |
| |
| /** |
| * get the composite control (Container) of source MultiPageEditorPart |
| * |
| * @return - the composite control (Container) |
| */ |
| private CTabFolder getContainerForMultiPageEditorPart() { |
| if (null == tabFolder) { |
| tabFolder = ((CTabFolder) (getSite().getPage().getActiveEditor() |
| .getAdapter(CTabFolder.class))); |
| } |
| return tabFolder; |
| } |
| |
| /** |
| * Removes a page record. If it is the last reference to the page dispose of |
| * it - otherwise just decrement the reference count. |
| * |
| * @param rec |
| */ |
| private void removePage(PageRec rec) { |
| mapPartToRec.remove(rec.part); |
| IPageSite site = (IPageSite) mapPageToSite.remove(rec.page); |
| |
| if (rec.subActionBars != null) { |
| rec.subActionBars.dispose(); |
| } |
| |
| Control control = rec.page.getControl(); |
| if (control != null && !control.isDisposed()) { |
| // Dispose the page's control so pages don't have to do this in |
| // their |
| // dispose method. |
| // The page's control is a child of this view's control so if this |
| // view |
| // is closed, the page's control will already be disposed. |
| control.dispose(); |
| } |
| |
| if (site instanceof SubPageSite) { |
| ((SubPageSite) site).dispose(); |
| } |
| |
| // free the page |
| doDestroyPage(rec.part, rec); |
| } |
| |
| /** |
| * Destroys a page in the pagebook for a particular part. |
| * |
| * @param part |
| * the input part |
| * @param rec |
| * a page record for the part |
| */ |
| protected void doDestroyPage(IWorkbenchPart part, PageRec rec) { |
| IContentOutlinePage page = (IContentOutlinePage) rec.page; |
| page.dispose(); |
| rec.dispose(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.part.Page#getControl() |
| */ |
| public Control getControl() { |
| return pageBook; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.part.Page#setFocus() |
| */ |
| public void setFocus() { |
| if (getControl() != null) { |
| getControl().setFocus(); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) |
| */ |
| public void addSelectionChangedListener(ISelectionChangedListener listener) { |
| selectionChangedListeners.add(listener); |
| |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection() |
| */ |
| public ISelection getSelection() { |
| // get the selection provider from the current page |
| IPage currentPage = getCurrentPage(); |
| // during workbench startup we may be in a state when |
| // there is no current page |
| if (currentPage == null) { |
| return StructuredSelection.EMPTY; |
| } |
| IPageSite site = getPageSite(currentPage); |
| if (site == null) { |
| return StructuredSelection.EMPTY; |
| } |
| ISelectionProvider selProvider = site.getSelectionProvider(); |
| if (selProvider != null) { |
| return selProvider.getSelection(); |
| } |
| return StructuredSelection.EMPTY; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) |
| */ |
| public void removeSelectionChangedListener( |
| ISelectionChangedListener listener) { |
| selectionChangedListeners.remove(listener); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection) |
| */ |
| public void setSelection(ISelection selection) { |
| // get the selection provider from the current page |
| IPage currentPage = getCurrentPage(); |
| // during workbench startup we may be in a state when |
| // there is no current page |
| if (currentPage == null) { |
| return; |
| } |
| IPageSite site = getPageSite(currentPage); |
| if (site == null) { |
| return; |
| } |
| ISelectionProvider selProvider = site.getSelectionProvider(); |
| // and set its selection |
| if (selProvider != null) { |
| selProvider.setSelection(selection); |
| } |
| } |
| |
| /** |
| * The selection has changed. Process the event. |
| * |
| * @param event |
| */ |
| public void pageSelectionChanged(final SelectionChangedEvent event) { |
| // pass on the notification to listeners |
| Object[] listeners = selectionChangedListeners.getListeners(); |
| for (int i = 0; i < listeners.length; ++i) { |
| final ISelectionChangedListener l = (ISelectionChangedListener) listeners[i]; |
| SafeRunner.run(new SafeRunnable() { |
| public void run() { |
| l.selectionChanged(event); |
| } |
| }); |
| } |
| |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see SelectionListener#widgetSelected(SelectionEvent) |
| */ |
| public void widgetSelected(SelectionEvent e) { |
| EditorPart part = (EditorPart) ((CTabItem) e.item).getData(); |
| |
| if (part != null) { |
| partActivated(part); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see SelectionListener#widgetDefaultSelected(SelectionEvent) |
| */ |
| public void widgetDefaultSelected(SelectionEvent e) { |
| // do nothing: no handling of default selected event |
| } |
| } |