replaced <code></code> with more concise {@code}
[idea/community.git] / platform / platform-api / src / com / intellij / openapi / actionSystem / AsyncUpdateAction.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.intellij.openapi.actionSystem;
18
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.util.concurrency.AppExecutorUtil;
21 import org.jetbrains.annotations.NotNull;
22
23 import javax.swing.*;
24 import java.util.concurrent.ExecutorService;
25
26 /**
27  * Base class for the actions, which update() method might be potentially slow to be executed synchronously in Swing UI thread.
28  *
29  * @author max
30  */
31 public abstract class AsyncUpdateAction<T> extends AnAction {
32   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.actionSystem.AsyncUpdateAction");
33
34   private static final ExecutorService ourUpdaterService = AppExecutorUtil.createBoundedApplicationPoolExecutor("AsyncUpdateAction pool", 1);
35
36   // Async update
37   @Override
38   public final void update(AnActionEvent e) {
39     final T data = prepareDataFromContext(e);
40     final Presentation originalPresentation = e.getPresentation();
41     if (!forceSyncUpdate(e) && isDumbAware()) {
42       final Presentation realPresentation = originalPresentation.clone();
43       ourUpdaterService.submit(() -> {
44         performUpdate(realPresentation, data);
45         SwingUtilities.invokeLater(() -> {
46           if (originalPresentation.isVisible() != realPresentation.isVisible()) {
47             LOG.error("Async update is not supported for actions that change their visibility." +
48                       "Either stop extending AsyncUpdateAction or override forceSyncUpdate() to return true." +
49                       "Action class is: " + this.getClass().getName());
50           }
51           originalPresentation.copyFrom(realPresentation);
52         });
53       });
54
55       originalPresentation.setVisible(true);
56       originalPresentation.setEnabled(false);
57     }
58     else {
59       performUpdate(originalPresentation, data);
60     }
61   }
62
63   // Sync update
64   @Override
65   public final void beforeActionPerformedUpdate(@NotNull AnActionEvent e) {
66     performUpdate(e.getPresentation(), prepareDataFromContext(e));
67   }
68
69   /**
70    * Get all necessary data from event's DataContext to be used in {@code performUpdate()}, which is called asynchronously.
71    * @param e action event original update() method have been called with.
72    * @return prepared data for {@link #performUpdate} method.
73    */
74   protected abstract T prepareDataFromContext(final AnActionEvent e);
75
76   /**
77    * Perform real presentation tweaking here. Be aware of the fact this method may be called in thread other than Swing UI thread thus
78    * probable restrictions like necessity to call ApplicationManager.getApplication().runReadAction() apply.
79    * @param presentation Presentation object to be tweaked.
80    * @param data necessary data calculated by {@link #prepareDataFromContext(AnActionEvent)}.
81    */
82   protected abstract void performUpdate(Presentation presentation, T data);
83
84   /**
85    * Override this method to return {@code true} value if update method cannot be called asynchronously for whatever reason.
86    * @param e action event original update() method have been called with.
87    * @return {@code false} if async update is possible and {@code false} otherwise.
88    */
89   protected boolean forceSyncUpdate(AnActionEvent e) {
90     return false;
91   }
92 }