org.eclipse.jface.text.link.LinkedModeManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
Tools from the AspectJ project
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.text.link;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.text.IDocument;
/**
* A linked mode manager ensures exclusive access of linked position infrastructures to documents. There
* is at most one LinkedModeManager
installed on the same document. The getManager
* methods will return the existing instance if any of the specified documents already have an installed
* manager.
*
* @since 3.0
*/
class LinkedModeManager {
/**
* Our implementation of ILinkedModeListener
.
*/
private class Listener implements ILinkedModeListener {
@Override
public void left(LinkedModeModel model, int flags) {
LinkedModeManager.this.left(model, flags);
}
@Override
public void suspend(LinkedModeModel model) {
// not interested
}
@Override
public void resume(LinkedModeModel model, int flags) {
// not interested
}
}
/** Global map from documents to managers. */
private static Map fgManagers= new HashMap<>();
/**
* Returns whether there exists a LinkedModeManager
on document
.
*
* @param document the document of interest
* @return true
if there exists a LinkedModeManager
on document
, false
otherwise
*/
public static boolean hasManager(IDocument document) {
return fgManagers.get(document) != null;
}
/**
* Returns whether there exists a LinkedModeManager
on any of the documents
.
*
* @param documents the documents of interest
* @return true
if there exists a LinkedModeManager
on any of the documents
, false
otherwise
*/
public static boolean hasManager(IDocument[] documents) {
for (IDocument document : documents) {
if (hasManager(document))
return true;
}
return false;
}
/**
* Returns the manager for the given documents. If force
is
* true
, any existing conflicting managers are canceled, otherwise,
* the method may return null
if there are conflicts.
*
* @param documents the documents of interest
* @param force whether to kill any conflicting managers
* @return a manager able to cover the requested documents, or null
if there is a conflict and force
was set to false
*/
public static LinkedModeManager getLinkedManager(IDocument[] documents, boolean force) {
if (documents == null || documents.length == 0)
return null;
Set mgrs= new HashSet<>();
LinkedModeManager mgr= null;
for (IDocument document : documents) {
mgr= fgManagers.get(document);
if (mgr != null)
mgrs.add(mgr);
}
if (mgrs.size() > 1)
if (force) {
for (LinkedModeManager m : mgrs) {
m.closeAllEnvironments();
}
} else {
return null;
}
if (mgrs.isEmpty())
mgr= new LinkedModeManager();
for (IDocument document : documents)
fgManagers.put(document, mgr);
return mgr;
}
/**
* Cancels any linked mode manager for the specified document.
*
* @param document the document whose LinkedModeManager
should be canceled
*/
public static void cancelManager(IDocument document) {
LinkedModeManager mgr= fgManagers.get(document);
if (mgr != null)
mgr.closeAllEnvironments();
}
/** The hierarchy of environments managed by this manager. */
private Stack fEnvironments= new Stack<>();
private Listener fListener= new Listener();
/**
* Notify the manager about a leaving model.
*
* @param model the model to nest
* @param flags the reason and commands for leaving linked mode
*/
private void left(LinkedModeModel model, int flags) {
if (!fEnvironments.contains(model))
return;
while (!fEnvironments.isEmpty()) {
LinkedModeModel env= fEnvironments.pop();
if (env == model)
break;
env.exit(ILinkedModeListener.NONE);
}
if (fEnvironments.isEmpty()) {
removeManager();
}
}
private void closeAllEnvironments() {
while (!fEnvironments.isEmpty()) {
LinkedModeModel env= fEnvironments.pop();
env.exit(ILinkedModeListener.NONE);
}
removeManager();
}
private void removeManager() {
for (Iterator it= fgManagers.values().iterator(); it.hasNext();) {
if (it.next() == this)
it.remove();
}
}
/**
* Tries to nest the given LinkedModeModel
onto the top of
* the stack of environments managed by the receiver. If force
* is true
, any environments on the stack that create a conflict
* are killed.
*
* @param model the model to nest
* @param force whether to force the addition of the model
* @return true
if nesting was successful, false
otherwise (only possible if force
is false
*/
public boolean nestEnvironment(LinkedModeModel model, boolean force) {
Assert.isNotNull(model);
try {
while (true) {
if (fEnvironments.isEmpty()) {
model.addLinkingListener(fListener);
fEnvironments.push(model);
return true;
}
LinkedModeModel top= fEnvironments.peek();
if (model.canNestInto(top)) {
model.addLinkingListener(fListener);
fEnvironments.push(model);
return true;
} else if (!force) {
return false;
} else { // force
fEnvironments.pop();
top.exit(ILinkedModeListener.NONE);
// continue;
}
}
} finally {
// if we remove any, make sure the new one got inserted
Assert.isTrue(!fEnvironments.isEmpty());
}
}
/**
* Returns the LinkedModeModel
that is on top of the stack of
* environments managed by the receiver.
*
* @return the topmost LinkedModeModel
*/
public LinkedModeModel getTopEnvironment() {
if (fEnvironments.isEmpty())
return null;
return fEnvironments.peek();
}
}