com.intellij.openapi.project.DumbService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core-api Show documentation
Show all versions of core-api Show documentation
A packaging of the IntelliJ Community Edition core-api library.
This is release number 1 of trunk branch 142.
The newest version!
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.project;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.ModificationTracker;
import com.intellij.openapi.util.NotNullLazyKey;
import com.intellij.openapi.util.Ref;
import com.intellij.util.messages.Topic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* A service managing IDEA's 'dumb' mode: when indices are updated in background and the functionality is very much limited.
* Only the explicitly allowed functionality is available. Usually it's allowed by implementing {@link DumbAware} interface.
*
* @author peter
*/
public abstract class DumbService {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.project.DumbService");
/**
* @see Project#getMessageBus()
*/
public static final Topic DUMB_MODE = new Topic("dumb mode", DumbModeListener.class);
/**
* The tracker is advanced each time we enter/exit from dumb mode.
*/
public abstract ModificationTracker getModificationTracker();
/**
* @return whether IntelliJ IDEA is in dumb mode, which means that right now indices are updated in background.
* IDEA offers only limited functionality at such times, e.g. plain text file editing and version control operations.
*/
public abstract boolean isDumb();
public static boolean isDumb(@NotNull Project project) {
return getInstance(project).isDumb();
}
/**
* Executes the runnable immediately if not in dumb mode, or on AWT Event Dispatch thread when the dumb mode ends.
* @param runnable runnable to run
*/
public abstract void runWhenSmart(@NotNull Runnable runnable);
/**
* Pause the current thread until dumb mode ends and then continue execution.
* NOTE: there are no guarantees that a new dumb mode won't begin before the next statement.
* Hence: use with care. Consider using {@link #runWhenSmart(Runnable)}, {@link #runReadActionInSmartMode(Runnable)} or {@link #repeatUntilPassesInSmartMode(Runnable)} instead
*/
public abstract void waitForSmartMode();
/**
* Pause the current thread until dumb mode ends, and then run the read action. Index is guaranteed to be available inside that read action.
*/
public T runReadActionInSmartMode(@NotNull final Computable r) {
final Ref result = new Ref();
runReadActionInSmartMode(new Runnable() {
@Override
public void run() {
result.set(r.compute());
}
});
return result.get();
}
@Nullable
public T tryRunReadActionInSmartMode(@NotNull Computable task, @Nullable String notification) {
if (ApplicationManager.getApplication().isReadAccessAllowed()) {
try {
return task.compute();
}
catch (IndexNotReadyException e) {
if (notification != null) {
showDumbModeNotification(notification);
}
return null;
}
}
else {
return runReadActionInSmartMode(task);
}
}
/**
* Pause the current thread until dumb mode ends, and then run the read action. Index is guaranteed to be available inside that read action.
*/
public void runReadActionInSmartMode(@NotNull final Runnable r) {
while (true) {
waitForSmartMode();
boolean success = ApplicationManager.getApplication().runReadAction(new Computable() {
@Override
public Boolean compute() {
if (isDumb()) {
return false;
}
r.run();
return true;
}
});
if (success) break;
}
}
/**
* Pause the current thread until dumb mode ends, and then attempt to execute the runnable. If it fails due to another dumb mode having started,
* try again until the runnable is able to complete successfully.
* It makes sense to use this method when you have a long-running activity consisting of many small read actions, and you don't want to
* use a single long read action in order to keep the IDE responsive.
*
* @see #runReadActionInSmartMode(Runnable)
*/
public void repeatUntilPassesInSmartMode(@NotNull final Runnable r) {
while (true) {
waitForSmartMode();
try {
r.run();
return;
}
catch (IndexNotReadyException e) {
LOG.info(e);
}
}
}
/**
* Invoke the runnable later on EventDispatchThread AND when IDEA isn't in dumb mode
* @param runnable runnable
*/
public abstract void smartInvokeLater(@NotNull Runnable runnable);
public abstract void smartInvokeLater(@NotNull Runnable runnable, @NotNull ModalityState modalityState);
private static final NotNullLazyKey INSTANCE_KEY = ServiceManager.createLazyKey(DumbService.class);
public static DumbService getInstance(@NotNull Project project) {
return INSTANCE_KEY.getValue(project);
}
/**
* @return all the elements of the given array if there's no dumb mode currently, or the dumb-aware ones if {@link #isDumb()} is true.
* @see #isDumbAware(Object)
*/
@NotNull
public List filterByDumbAwareness(@NotNull T[] array) {
return filterByDumbAwareness(Arrays.asList(array));
}
/**
* @return all the elements of the given collection if there's no dumb mode currently, or the dumb-aware ones if {@link #isDumb()} is true.
* @see #isDumbAware(Object)
*/
@NotNull
public List filterByDumbAwareness(@NotNull Collection collection) {
if (isDumb()) {
final ArrayList result = new ArrayList(collection.size());
for (T element : collection) {
if (isDumbAware(element)) {
result.add(element);
}
}
return result;
}
if (collection instanceof List) {
return (List)collection;
}
return new ArrayList(collection);
}
public abstract void queueTask(@NotNull DumbModeTask task);
public abstract void cancelTask(@NotNull DumbModeTask task);
public abstract JComponent wrapGently(@NotNull JComponent dumbUnawareContent, @NotNull Disposable parentDisposable);
public void makeDumbAware(@NotNull final JComponent component, @NotNull Disposable disposable) {
component.setEnabled(!isDumb());
getProject().getMessageBus().connect(disposable).subscribe(DUMB_MODE, new DumbModeListener() {
@Override
public void enteredDumbMode() {
component.setEnabled(false);
}
@Override
public void exitDumbMode() {
component.setEnabled(true);
}
});
}
public abstract void showDumbModeNotification(@NotNull String message);
public abstract Project getProject();
public static boolean isDumbAware(Object o) {
if (o instanceof PossiblyDumbAware) {
return ((PossiblyDumbAware)o).isDumbAware();
}
return o instanceof DumbAware;
}
/**
* Enables or disables alternative resolve strategies for the current thread.
*
* Normally reference resolution uses index, and hence is not available in dumb mode. In some cases, alternative ways
* of performing resolve are available, although much slower. It's impractical to always use these ways because it'll
* lead to overloaded CPU (especially given there's also indexing in progress). But for some explicit user actions
* (e.g. explicit Goto Declaration) turning these slower methods is beneficial.
*
* NOTE: even with alternative resolution enabled, methods like resolve(), findClass() etc may still throw
* {@link IndexNotReadyException}. So alternative resolve is not a panacea, it might help provide navigation in some cases
* but not in all.
*
* A typical usage would involve try-finally, where the alternative resolution is first enabled, then an action is performed,
* and then alternative resolution is turned off in the finally block.
*/
public abstract void setAlternativeResolveEnabled(boolean enabled);
/**
* Invokes the given runnable with alternative resolve set to true.
* @see #setAlternativeResolveEnabled(boolean)
*/
public void withAlternativeResolveEnabled(@NotNull Runnable runnable) {
setAlternativeResolveEnabled(true);
try {
runnable.run();
}
finally {
setAlternativeResolveEnabled(false);
}
}
/**
* @return whether alternative resolution is enabled for the current thread.
*
* @see #setAlternativeResolveEnabled(boolean)
*/
public abstract boolean isAlternativeResolveEnabled();
/**
* @see #DUMB_MODE
*/
public interface DumbModeListener {
/**
* The event arrives on EDT
*/
void enteredDumbMode();
/**
* The event arrives on EDT
*/
void exitDumbMode();
}
}