blob: 920910ba337a79403cd90c8f83e6f222f976bbd6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2012 Oracle. 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:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.jpa.ui.internal.selection;
import java.util.HashMap;
import java.util.HashSet;
import org.eclipse.jpt.common.ui.internal.utility.PartAdapter2;
import org.eclipse.jpt.common.utility.internal.StringTools;
import org.eclipse.jpt.common.utility.internal.Transformer;
import org.eclipse.jpt.common.utility.internal.AbstractTransformer;
import org.eclipse.jpt.common.utility.internal.model.value.DoubleModifiablePropertyValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.DoublePropertyValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.TransformationPropertyValueModel;
import org.eclipse.jpt.common.utility.model.value.PropertyValueModel;
import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
import org.eclipse.jpt.jpa.core.JpaFile;
import org.eclipse.jpt.jpa.core.JpaStructureNode;
import org.eclipse.jpt.jpa.ui.selection.JpaEditorManager;
import org.eclipse.jpt.jpa.ui.selection.JpaSelectionManager;
import org.eclipse.jpt.jpa.ui.selection.JpaViewManager;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
/**
* Maintain:<ul>
* <li>a collection of {@link JpaEditorManager JPA editor managers}
* for the page's {@link IEditorPart editors}: The page manager creates
* and disposes the editor managers. The editor manager is the <em>master</em>
* part manager and holds the JPA file and JPA selection models that can be
* used by the {@link #viewManagers view managers} and/or the page manager.
* <li>a collection of {@link JpaViewManager JPA view managers}
* for the page's JPA {@link IViewPart views}: The JPA views themselves create
* and dispose the {@link #viewManagers view managers}.
* </ul>
* Forward the JPA selection to the active editor manager's JPA selection model,
* which should notify the appropriate view managers etc.
*/
class JpaPageManager
implements JpaSelectionManager, JpaViewManager.PageManager
{
/**
* The manager's parent window manager.
*/
private final JpaWindowManager windowManager;
/**
* The manager's page.
*/
private final IWorkbenchPage page;
/**
* Editor managers keyed by corresponding editor.
* Lazily populated as managers are requested by
* {@link #viewManagers view managers}.
*/
private final HashMap<IEditorPart, JpaEditorManager> editorManagers = new HashMap<IEditorPart, JpaEditorManager>();
/**
* Model that holds the editor manager corresponding to the active editor.
*/
private final SimplePropertyValueModel<JpaEditorManager> editorManagerModel = new SimplePropertyValueModel<JpaEditorManager>();
/**
* The page's current JPA file. This wraps the current editor manager's
* JPA file model. It can be modified only by the editor manager.
*/
private final PropertyValueModel<JpaFile> jpaFileModel;
/**
* The page's current JPA selection. This wraps the current editor manager's
* JPA selection model. It can be modified by either the editor manager or
* any view manager.
*/
private final ModifiablePropertyValueModel<JpaStructureNode> jpaSelectionModel;
/**
* Listen to {@link #page} to maintain {@link #editorManagers}.
*/
private final IPartListener2 partListener = new PartListener();
/**
* List of view managers for the page's JPA views.
* This is maintained by the JPA views themselves.
* It should be empty only immediately after construction
* and immediately before disposal.
*/
private final HashSet<JpaViewManager> viewManagers = new HashSet<JpaViewManager>();
private volatile boolean disposed = false;
JpaPageManager(JpaWindowManager windowManager, IWorkbenchPage page) {
super();
if (page == null) {
throw new NullPointerException();
}
this.windowManager = windowManager;
this.page = page;
this.jpaFileModel = this.buildJpaFileModel();
this.jpaSelectionModel = this.buildJpaSelectionModel();
this.page.addPartListener(this.partListener);
this.updateEditorManagerModel();
}
// ********** JPA file model **********
public PropertyValueModel<JpaFile> getJpaFileModel() {
return this.jpaFileModel;
}
private PropertyValueModel<JpaFile> buildJpaFileModel() {
return new DoublePropertyValueModel<JpaFile>(this.buildEditorManagerJpaFileModel());
}
private PropertyValueModel<PropertyValueModel<JpaFile>> buildEditorManagerJpaFileModel() {
return new TransformationPropertyValueModel<JpaEditorManager, PropertyValueModel<JpaFile>>(this.editorManagerModel, JPA_FILE_MODEL_TRANSFORMER);
}
private static final Transformer<JpaEditorManager, PropertyValueModel<JpaFile>> JPA_FILE_MODEL_TRANSFORMER = new JpaFileModelTransformer();
/* CU private */ static class JpaFileModelTransformer
extends AbstractTransformer<JpaEditorManager, PropertyValueModel<JpaFile>>
{
@Override
public PropertyValueModel<JpaFile> transform_(JpaEditorManager editorManager) {
return editorManager.getJpaFileModel();
}
}
// ********** JPA selection model **********
public ModifiablePropertyValueModel<JpaStructureNode> getJpaSelectionModel() {
return this.jpaSelectionModel;
}
private ModifiablePropertyValueModel<JpaStructureNode> buildJpaSelectionModel() {
return new DoubleModifiablePropertyValueModel<JpaStructureNode>(this.buildEditorManagerJpaSelectionModel());
}
private PropertyValueModel<ModifiablePropertyValueModel<JpaStructureNode>> buildEditorManagerJpaSelectionModel() {
return new TransformationPropertyValueModel<JpaEditorManager, ModifiablePropertyValueModel<JpaStructureNode>>(this.editorManagerModel, JPA_SELECTION_MODEL_TRANSFORMER);
}
private static final Transformer<JpaEditorManager, ModifiablePropertyValueModel<JpaStructureNode>> JPA_SELECTION_MODEL_TRANSFORMER = new JpaSelectionModelTransformer();
/* CU private */ static class JpaSelectionModelTransformer
extends AbstractTransformer<JpaEditorManager, ModifiablePropertyValueModel<JpaStructureNode>>
{
@Override
public ModifiablePropertyValueModel<JpaStructureNode> transform_(JpaEditorManager editorManager) {
return editorManager.getJpaSelectionModel();
}
}
// ********** selection **********
/**
* This should only be called from the
* {@link #windowManager window manager}.
*/
public void setSelection(JpaStructureNode selection) {
this.jpaSelectionModel.setValue(selection);
}
// ********** editor managers **********
public JpaEditorManager getEditorManager(IEditorPart editor) {
return (editor == null) ? null : this.getEditorManager_(editor);
}
private synchronized JpaEditorManager getEditorManager_(IEditorPart editor) {
JpaEditorManager editorManager = this.editorManagers.get(editor);
if (editorManager == null) {
editorManager = this.buildEditorManager(editor);
if (editorManager != null) {
JpaWorkbenchManager.debug("add editor manager:", editor); //$NON-NLS-1$
this.editorManagers.put(editor, editorManager);
}
}
return editorManager;
}
/**
* <strong>NB:</strong> The editor manager is built once (when first
* requested by a view manager) and not disposed until all the view
* managers are removed from the page manager. As a result, the editor
* manager is most likely driven by the class of the editor, as opposed
* to the editor's content....
*/
private JpaEditorManager buildEditorManager(IEditorPart editor) {
return (JpaEditorManager) editor.getAdapter(JpaEditorManager.class);
}
// ********** view managers **********
public synchronized void addViewManager(JpaViewManager viewManager) {
JpaWorkbenchManager.debug("add view manager:", viewManager); //$NON-NLS-1$
if (this.disposed) {
// This can happen if the page manager's last view manager is removed
// after a page manager was returned to a new view manager but before that
// view manager adds itself to the page manager....
throw new IllegalStateException("page manager is disposed: " + this); //$NON-NLS-1$
}
if ( ! this.viewManagers.add(viewManager)) {
throw new IllegalArgumentException("duplicate view manager: " + viewManager); //$NON-NLS-1$
}
}
public synchronized void removeViewManager(JpaViewManager viewManager) {
JpaWorkbenchManager.debug("remove view manager:", viewManager); //$NON-NLS-1$
if ( ! this.viewManagers.remove(viewManager)) {
throw new IllegalArgumentException("missing view manager: " + viewManager); //$NON-NLS-1$
}
if (this.viewManagers.isEmpty()) {
this.dispose();
}
}
// ********** misc **********
/**
* When all the view managers are gone we get rid of the page manager.
*/
private void dispose() {
this.disposed = true;
this.page.removePartListener(this.partListener);
for (JpaEditorManager editorManager : this.editorManagers.values()) {
editorManager.dispose();
}
this.windowManager.removePageManager(this.page);
}
@Override
public String toString() {
return StringTools.buildToStringFor(this, this.page);
}
// ********** part listener **********
/**
* Remove the corresponding editor manager whenever an editor is closed.
*/
/* CU private */ class PartListener
extends PartAdapter2
{
@Override
public void partActivated(IWorkbenchPartReference partRef) {
JpaPageManager.this.updateEditorManagerModel();
}
@Override
public void partBroughtToTop(IWorkbenchPartReference partRef) {
JpaPageManager.this.updateEditorManagerModel();
}
@Override
public void partClosed(IWorkbenchPartReference partRef) {
IWorkbenchPart part = partRef.getPart(false);
if (part != null) {
JpaPageManager.this.partClosed(part);
}
}
}
/* CU private */ synchronized void partClosed(IWorkbenchPart part) {
JpaEditorManager editorManager = this.editorManagers.remove(part);
if (editorManager != null) {
JpaWorkbenchManager.debug("removed editor manager:", part); //$NON-NLS-1$
editorManager.dispose();
}
this.updateEditorManagerModel();
}
/* CU private */ void updateEditorManagerModel() {
this.editorManagerModel.setValue(this.getEditorManager(this.page.getActiveEditor()));
}
}