| /******************************************************************************* |
| * Copyright (c) 2001, 2008 Oracle Corporation 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: |
| * Oracle Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.jsf.ui.internal.component; |
| |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.IJobChangeEvent; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.core.runtime.jobs.JobChangeAdapter; |
| import org.eclipse.jst.jsf.context.resolver.structureddocument.IStructuredDocumentContextResolverFactory; |
| import org.eclipse.jst.jsf.context.resolver.structureddocument.IWorkspaceContextResolver; |
| import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext; |
| import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContextFactory; |
| import org.eclipse.jst.jsf.designtime.DTAppManagerUtil; |
| import org.eclipse.jst.jsf.designtime.DesignTimeApplicationManager; |
| import org.eclipse.jst.jsf.designtime.context.DTFacesContext; |
| import org.eclipse.jst.jsf.designtime.internal.view.DTUIViewRoot; |
| import org.eclipse.jst.jsf.designtime.internal.view.IDTViewHandler; |
| import org.eclipse.jst.jsf.designtime.internal.view.IViewRootHandle; |
| import org.eclipse.jst.jsf.designtime.internal.view.DTUIViewRoot.StalenessEvent; |
| import org.eclipse.jst.jsf.designtime.internal.view.DTUIViewRoot.StalenessListener; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; |
| |
| /** |
| * The top-level input model for a design time component tree |
| * |
| * @author cbateman |
| * |
| */ |
| /* package */class DTJSFViewModel |
| { |
| private final IStructuredDocument _document; |
| private final IProject _project; |
| private final IFile _file; |
| private final IStructuredDocumentContext _context; |
| private final AtomicBoolean _alreadyUpdating = new AtomicBoolean( |
| false); |
| private Runnable _runnable; |
| private final IViewRootHandle _viewRootHandle; |
| private StalenessListener _stalenessListener; |
| |
| /** |
| * @param document |
| * @throws IllegalArgumentException |
| * if document cannot be used to initialize a component tree. |
| */ |
| public DTJSFViewModel(final IStructuredDocument document) |
| { |
| _document = document; |
| _context = IStructuredDocumentContextFactory.INSTANCE.getContext( |
| _document, -1); |
| |
| final IWorkspaceContextResolver resolver = IStructuredDocumentContextResolverFactory.INSTANCE |
| .getWorkspaceContextResolver(_context); |
| |
| if (resolver == null) |
| { |
| throw new IllegalArgumentException(); |
| } |
| |
| _project = resolver.getProject(); |
| _file = (IFile) resolver.getResource(); |
| |
| if (_project == null || _file == null) |
| { |
| throw new IllegalArgumentException(); |
| } |
| |
| final DTFacesContext facesContext = getFacesContext(); |
| _viewRootHandle = facesContext.getViewRootHandle(); |
| } |
| |
| /** |
| * Acquire and initialize the component tree root for the document |
| * |
| * @param runnable |
| */ |
| public void init(final Runnable runnable) |
| { |
| _runnable = runnable; |
| _viewRootHandle.addListener(getOrCreateListener()); |
| } |
| |
| public void dispose() |
| { |
| if (_stalenessListener != null) |
| { |
| _viewRootHandle.removeListener(_stalenessListener); |
| } |
| |
| synchronized(this) |
| { |
| _runnable = null; |
| } |
| } |
| |
| /** |
| * @return the structured document that this view model was created for. |
| */ |
| public final IStructuredDocument getDocument() |
| { |
| return _document; |
| } |
| |
| public final IProject getProject() |
| { |
| return _project; |
| } |
| |
| public final IFile getFile() |
| { |
| return _file; |
| } |
| |
| public final String getViewId() |
| { |
| final DTFacesContext facesContext = getFacesContext(); |
| final IDTViewHandler viewHandler = DTAppManagerUtil |
| .getViewHandler(_project); |
| if (facesContext != null && viewHandler != null) |
| { |
| return viewHandler.getViewId(facesContext, _file); |
| } |
| return null; |
| } |
| |
| private DTFacesContext getFacesContext() |
| { |
| final DesignTimeApplicationManager manager = DesignTimeApplicationManager |
| .getInstance(_project); |
| |
| if (manager != null) |
| { |
| return manager.getFacesContext(_file); |
| } |
| return null; |
| } |
| |
| public void update() |
| { |
| final DTFacesContext facesContext = getFacesContext(); |
| |
| if (facesContext != null) |
| { |
| // latch the alreadyRunning flag; job will unset to false |
| if (_alreadyUpdating.compareAndSet(false, true)) |
| { |
| final Job job = new UpdateRootAndRefreshJob(_viewRootHandle); |
| |
| job.addJobChangeListener(new JobChangeAdapter() |
| { |
| @Override |
| public void done(final IJobChangeEvent event) |
| { |
| // always reset the updating flag |
| _alreadyUpdating.set(false); |
| if (event.getResult().isOK()) |
| { |
| synchronized(DTJSFViewModel.this) |
| { |
| if (_runnable != null) |
| { |
| _runnable.run(); |
| } |
| } |
| } |
| } |
| }); |
| |
| job.schedule(); |
| } |
| } |
| } |
| |
| /** |
| * @return the design time view root or null |
| */ |
| public DTUIViewRoot getRoot() |
| { |
| final DTFacesContext facesContext = getFacesContext(); |
| |
| if (facesContext != null) |
| { |
| final DTUIViewRoot viewRoot = _viewRootHandle.getCachedViewRoot(); |
| |
| // if our copy is uninit or null, kick off an update |
| if (viewRoot == null || viewRoot.isStale()) |
| { |
| update(); |
| } |
| |
| return viewRoot; |
| } |
| return null; |
| } |
| |
| private StalenessListener getOrCreateListener() |
| { |
| if (_stalenessListener == null) |
| { |
| _stalenessListener = new StalenessListener() |
| { |
| @Override |
| protected void stalenessChanged(StalenessEvent event) |
| { |
| switch (event.getChangeType()) |
| { |
| case VIEW_DEFN_CHANGED: |
| case PROJECT_CLEANED: |
| { |
| update(); |
| } |
| case VIEW_DEFN_DELETED: |
| case VIEW_DEFN_PROJECT_CLOSED: |
| { |
| DTUIViewRoot root = _viewRootHandle |
| .getCachedViewRoot(); |
| if (root != null) |
| { |
| root.removeListener(_stalenessListener); |
| } |
| } |
| } |
| } |
| }; |
| } |
| return _stalenessListener; |
| } |
| |
| private static class UpdateRootAndRefreshJob extends Job |
| { |
| private final IViewRootHandle _viewRootHandle; |
| |
| public UpdateRootAndRefreshJob(final IViewRootHandle viewRootHandle) |
| { |
| super(Messages.DTJSFViewModel_JobDesc); |
| _viewRootHandle = viewRootHandle; |
| } |
| |
| @Override |
| protected IStatus run(final IProgressMonitor monitor) |
| { |
| _viewRootHandle.updateViewRoot(); |
| return Status.OK_STATUS; |
| } |
| } |
| } |