| /* |
| * 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.wm.impl.status; |
| |
| import com.intellij.ide.ui.UISettings; |
| import com.intellij.idea.ActionsBundle; |
| import com.intellij.notification.EventLog; |
| import com.intellij.openapi.actionSystem.ActionGroup; |
| import com.intellij.openapi.actionSystem.ActionManager; |
| import com.intellij.openapi.actionSystem.ActionPlaces; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.editor.impl.EditorComponentImpl; |
| import com.intellij.openapi.progress.ProgressIndicator; |
| import com.intellij.openapi.progress.TaskInfo; |
| import com.intellij.openapi.ui.MessageType; |
| import com.intellij.openapi.ui.popup.Balloon; |
| import com.intellij.openapi.ui.popup.BalloonHandler; |
| import com.intellij.openapi.ui.popup.JBPopupFactory; |
| import com.intellij.openapi.util.*; |
| import com.intellij.openapi.util.registry.Registry; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.openapi.wm.CustomStatusBarWidget; |
| import com.intellij.openapi.wm.StatusBar; |
| import com.intellij.openapi.wm.StatusBarWidget; |
| import com.intellij.openapi.wm.ex.ProgressIndicatorEx; |
| import com.intellij.ui.Gray; |
| import com.intellij.ui.awt.RelativePoint; |
| import com.intellij.ui.components.labels.LinkLabel; |
| import com.intellij.ui.components.labels.LinkListener; |
| import com.intellij.ui.components.panels.Wrapper; |
| import com.intellij.util.Alarm; |
| import com.intellij.util.ui.*; |
| import com.intellij.util.ui.update.MergingUpdateQueue; |
| import com.intellij.util.ui.update.Update; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import javax.swing.border.EmptyBorder; |
| import javax.swing.event.HyperlinkListener; |
| import java.awt.*; |
| import java.awt.event.MouseAdapter; |
| import java.awt.event.MouseEvent; |
| import java.util.*; |
| import java.util.List; |
| |
| public class InfoAndProgressPanel extends JPanel implements CustomStatusBarWidget { |
| private final ProcessPopup myPopup; |
| |
| private final StatusPanel myInfoPanel = new StatusPanel(); |
| private final JPanel myRefreshAndInfoPanel = new JPanel(); |
| private final AnimatedIcon myProgressIcon; |
| |
| private final ArrayList<ProgressIndicatorEx> myOriginals = new ArrayList<ProgressIndicatorEx>(); |
| private final ArrayList<TaskInfo> myInfos = new ArrayList<TaskInfo>(); |
| private final Map<InlineProgressIndicator, ProgressIndicatorEx> myInline2Original |
| = new HashMap<InlineProgressIndicator, ProgressIndicatorEx>(); |
| private final MultiValuesMap<ProgressIndicatorEx, InlineProgressIndicator> myOriginal2Inlines |
| = new MultiValuesMap<ProgressIndicatorEx, InlineProgressIndicator>(); |
| |
| private final MergingUpdateQueue myUpdateQueue; |
| private final Alarm myQueryAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); |
| |
| private boolean myShouldClosePopupAndOnProcessFinish; |
| |
| private final Alarm myRefreshAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); |
| private final AnimatedIcon myRefreshIcon; |
| |
| private String myCurrentRequestor; |
| |
| public InfoAndProgressPanel() { |
| |
| setOpaque(false); |
| |
| myRefreshIcon = new RefreshFileSystemIcon(); |
| // new AsyncProcessIcon("Refreshing filesystem") { |
| // protected Icon getPassiveIcon() { |
| // return myEmptyRefreshIcon; |
| // } |
| // |
| // @Override |
| // public Dimension getPreferredSize() { |
| // if (!isRunning()) return new Dimension(0, 0); |
| // return super.getPreferredSize(); |
| // } |
| // |
| // @Override |
| // public void paint(Graphics g) { |
| // g.translate(0, -1); |
| // super.paint(g); |
| // g.translate(0, 1); |
| // } |
| //}; |
| |
| myRefreshIcon.setPaintPassiveIcon(false); |
| |
| myRefreshAndInfoPanel.setLayout(new BorderLayout()); |
| myRefreshAndInfoPanel.setOpaque(false); |
| myRefreshAndInfoPanel.add(myRefreshIcon, BorderLayout.WEST); |
| myRefreshAndInfoPanel.add(myInfoPanel, BorderLayout.CENTER); |
| |
| myProgressIcon = new AsyncProcessIcon("Background process"); |
| myProgressIcon.setOpaque(false); |
| |
| myProgressIcon.addMouseListener(new MouseAdapter() { |
| @Override |
| public void mousePressed(MouseEvent e) { |
| handle(e); |
| } |
| @Override |
| public void mouseReleased(MouseEvent e) { |
| handle(e); |
| } |
| }); |
| |
| myProgressIcon.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); |
| myProgressIcon.setBorder(StatusBarWidget.WidgetBorder.INSTANCE); |
| myProgressIcon.setToolTipText(ActionsBundle.message("action.ShowProcessWindow.double.click")); |
| |
| myUpdateQueue = new MergingUpdateQueue("Progress indicator", 50, true, MergingUpdateQueue.ANY_COMPONENT); |
| myPopup = new ProcessPopup(this); |
| |
| setRefreshVisible(false); |
| |
| restoreEmptyStatus(); |
| } |
| |
| private void handle(MouseEvent e) { |
| if (UIUtil.isActionClick(e, MouseEvent.MOUSE_PRESSED)) { |
| if (!myPopup.isShowing()) { |
| openProcessPopup(true); |
| } else { |
| hideProcessPopup(); |
| } |
| } else if (e.isPopupTrigger()) { |
| ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction("BackgroundTasks"); |
| ActionManager.getInstance().createActionPopupMenu(ActionPlaces.UNKNOWN, group).getComponent().show(e.getComponent(), e.getX(), e.getY()); |
| } |
| } |
| |
| @Override |
| @NotNull |
| public String ID() { |
| return "InfoAndProgress"; |
| } |
| |
| @Override |
| public WidgetPresentation getPresentation(@NotNull PlatformType type) { |
| return null; |
| } |
| |
| @Override |
| public void install(@NotNull StatusBar statusBar) { |
| } |
| |
| @Override |
| public void dispose() { |
| setRefreshVisible(false); |
| InlineProgressIndicator[] indicators = getCurrentInlineIndicators().toArray(new InlineProgressIndicator[0]); |
| for (InlineProgressIndicator indicator : indicators) { |
| Disposer.dispose(indicator); |
| } |
| myInline2Original.clear(); |
| myOriginal2Inlines.clear(); |
| } |
| |
| @Override |
| public JComponent getComponent() { |
| return this; |
| } |
| |
| @NotNull |
| public List<Pair<TaskInfo, ProgressIndicator>> getBackgroundProcesses() { |
| synchronized (myOriginals) { |
| if (myOriginals.isEmpty()) return Collections.emptyList(); |
| |
| List<Pair<TaskInfo, ProgressIndicator>> result = new ArrayList<Pair<TaskInfo, ProgressIndicator>>(myOriginals.size()); |
| for (int i = 0; i < myOriginals.size(); i++) { |
| result.add(Pair.<TaskInfo, ProgressIndicator>create(myInfos.get(i), myOriginals.get(i))); |
| } |
| |
| return Collections.unmodifiableList(result); |
| } |
| } |
| |
| public void addProgress(@NotNull ProgressIndicatorEx original, @NotNull TaskInfo info) { |
| synchronized (myOriginals) { |
| final boolean veryFirst = !hasProgressIndicators(); |
| |
| myOriginals.add(original); |
| myInfos.add(info); |
| |
| final InlineProgressIndicator expanded = createInlineDelegate(info, original, false); |
| final InlineProgressIndicator compact = createInlineDelegate(info, original, true); |
| |
| myPopup.addIndicator(expanded); |
| myProgressIcon.resume(); |
| |
| if (veryFirst && !myPopup.isShowing()) { |
| buildInInlineIndicator(compact); |
| } |
| else { |
| buildInProcessCount(); |
| if (myInfos.size() > 1 && Registry.is("ide.windowSystem.autoShowProcessPopup")) { |
| openProcessPopup(false); |
| } |
| } |
| |
| runQuery(); |
| } |
| } |
| |
| private boolean hasProgressIndicators() { |
| synchronized (myOriginals) { |
| return !myOriginals.isEmpty(); |
| } |
| } |
| |
| private void removeProgress(@NotNull InlineProgressIndicator progress) { |
| synchronized (myOriginals) { |
| if (!myInline2Original.containsKey(progress)) return; |
| |
| final boolean last = myOriginals.size() == 1; |
| final boolean beforeLast = myOriginals.size() == 2; |
| |
| myPopup.removeIndicator(progress); |
| |
| final ProgressIndicatorEx original = removeFromMaps(progress); |
| if (myOriginals.contains(original)) return; |
| |
| if (last) { |
| restoreEmptyStatus(); |
| if (myShouldClosePopupAndOnProcessFinish) { |
| hideProcessPopup(); |
| } |
| } |
| else { |
| if (myPopup.isShowing() || myOriginals.size() > 1) { |
| buildInProcessCount(); |
| } |
| else if (beforeLast) { |
| buildInInlineIndicator(createInlineDelegate(myInfos.get(0), myOriginals.get(0), true)); |
| } |
| else { |
| restoreEmptyStatus(); |
| } |
| } |
| |
| runQuery(); |
| } |
| } |
| |
| private ProgressIndicatorEx removeFromMaps(@NotNull InlineProgressIndicator progress) { |
| final ProgressIndicatorEx original = myInline2Original.get(progress); |
| |
| myInline2Original.remove(progress); |
| |
| myOriginal2Inlines.remove(original, progress); |
| if (myOriginal2Inlines.get(original) == null) { |
| final int originalIndex = myOriginals.indexOf(original); |
| myOriginals.remove(originalIndex); |
| myInfos.remove(originalIndex); |
| } |
| |
| return original; |
| } |
| |
| private void openProcessPopup(boolean requestFocus) { |
| synchronized (myOriginals) { |
| if (myPopup.isShowing()) return; |
| if (hasProgressIndicators()) { |
| myShouldClosePopupAndOnProcessFinish = true; |
| buildInProcessCount(); |
| } |
| else { |
| myShouldClosePopupAndOnProcessFinish = false; |
| restoreEmptyStatus(); |
| } |
| myPopup.show(requestFocus); |
| } |
| } |
| |
| void hideProcessPopup() { |
| synchronized (myOriginals) { |
| if (!myPopup.isShowing()) return; |
| |
| if (myOriginals.size() == 1) { |
| buildInInlineIndicator(createInlineDelegate(myInfos.get(0), myOriginals.get(0), true)); |
| } |
| else if (!hasProgressIndicators()) { |
| restoreEmptyStatus(); |
| } |
| else { |
| buildInProcessCount(); |
| } |
| |
| myPopup.hide(); |
| } |
| } |
| |
| private void buildInProcessCount() { |
| removeAll(); |
| setLayout(new BorderLayout()); |
| |
| final JPanel progressCountPanel = new JPanel(new BorderLayout(0, 0)); |
| progressCountPanel.setOpaque(false); |
| String processWord = myOriginals.size() == 1 ? " process" : " processes"; |
| final LinkLabel label = new LinkLabel(myOriginals.size() + processWord + " running...", null, new LinkListener() { |
| @Override |
| public void linkSelected(final LinkLabel aSource, final Object aLinkData) { |
| triggerPopupShowing(); |
| } |
| }); |
| |
| if (SystemInfo.isMac) label.setFont(UIUtil.getLabelFont().deriveFont(11.0f)); |
| |
| label.setOpaque(false); |
| |
| final Wrapper labelComp = new Wrapper(label); |
| labelComp.setOpaque(false); |
| progressCountPanel.add(labelComp, BorderLayout.CENTER); |
| |
| //myProgressIcon.setBorder(new IdeStatusBarImpl.MacStatusBarWidgetBorder()); |
| progressCountPanel.add(myProgressIcon, BorderLayout.WEST); |
| |
| add(myRefreshAndInfoPanel, BorderLayout.CENTER); |
| |
| progressCountPanel.setBorder(new EmptyBorder(0, 0, 0, 4)); |
| add(progressCountPanel, BorderLayout.EAST); |
| |
| revalidate(); |
| repaint(); |
| } |
| |
| private void buildInInlineIndicator(@NotNull final InlineProgressIndicator inline) { |
| removeAll(); |
| setLayout(new InlineLayout()); |
| add(myRefreshAndInfoPanel); |
| |
| final JPanel inlinePanel = new JPanel(new BorderLayout()); |
| |
| inline.getComponent().setBorder(new EmptyBorder(1, 0, 0, 2)); |
| final JComponent inlineComponent = inline.getComponent(); |
| inlineComponent.setOpaque(false); |
| inlinePanel.add(inlineComponent, BorderLayout.CENTER); |
| |
| //myProgressIcon.setBorder(new IdeStatusBarImpl.MacStatusBarWidgetBorder()); |
| inlinePanel.add(myProgressIcon, BorderLayout.WEST); |
| |
| inline.updateProgressNow(); |
| inlinePanel.setOpaque(false); |
| |
| add(inlinePanel); |
| |
| myRefreshAndInfoPanel.revalidate(); |
| myRefreshAndInfoPanel.repaint(); |
| |
| UISettings uiSettings = UISettings.getInstance(); |
| if (uiSettings.PRESENTATION_MODE || !uiSettings.SHOW_STATUS_BAR && Registry.is("ide.show.progress.without.status.bar")) { |
| final JRootPane pane = myInfoPanel.getRootPane(); |
| final RelativePoint point = new RelativePoint(pane, new Point(pane.getWidth() - 250, 60)); |
| final PresentationModeProgressPanel panel = new PresentationModeProgressPanel(inline); |
| final MyInlineProgressIndicator delegate = new MyInlineProgressIndicator(true, inline.getInfo(), inline) { |
| @Override |
| protected void updateProgress() { |
| super.updateProgress(); |
| panel.update(); |
| } |
| }; |
| |
| Disposer.register(inline, delegate); |
| |
| JBPopupFactory.getInstance().createBalloonBuilder(panel.getRootPanel()) |
| .setFadeoutTime(0) |
| .setFillColor(Gray.TRANSPARENT) |
| .setShowCallout(false) |
| .setBorderColor(Gray.TRANSPARENT) |
| .setBorderInsets(new Insets(0, 0, 0, 0)) |
| .setAnimationCycle(0) |
| .setCloseButtonEnabled(false) |
| .setHideOnClickOutside(false) |
| .setDisposable(inline) |
| .setHideOnFrameResize(false) |
| .setHideOnKeyOutside(false) |
| .setBlockClicksThroughBalloon(true) |
| .setHideOnAction(false) |
| .createBalloon().show(new PositionTracker<Balloon>(pane) { |
| @Override |
| public RelativePoint recalculateLocation(Balloon object) { |
| final EditorComponentImpl editorComponent = UIUtil.findComponentOfType(pane, EditorComponentImpl.class); |
| if (editorComponent != null) { |
| return new RelativePoint(editorComponent.getParent().getParent(), new Point(editorComponent.getParent().getParent().getWidth() - 150, editorComponent.getParent().getParent().getHeight() - 70)); |
| } |
| return point; |
| } |
| }, Balloon.Position.above); |
| } |
| } |
| |
| public Couple<String> setText(@Nullable final String text, @Nullable final String requestor) { |
| if (StringUtil.isEmpty(text) && !Comparing.equal(requestor, myCurrentRequestor) && !EventLog.LOG_REQUESTOR.equals(requestor)) { |
| return Couple.of(myInfoPanel.getText(), myCurrentRequestor); |
| } |
| |
| boolean logMode = myInfoPanel.updateText(EventLog.LOG_REQUESTOR.equals(requestor) ? "" : text); |
| myCurrentRequestor = logMode ? EventLog.LOG_REQUESTOR : requestor; |
| return Couple.of(text, requestor); |
| } |
| |
| public void setRefreshVisible(final boolean visible) { |
| UIUtil.invokeLaterIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| myRefreshAlarm.cancelAllRequests(); |
| myRefreshAlarm.addRequest(new Runnable() { |
| @Override |
| public void run() { |
| if (visible) { |
| myRefreshIcon.resume(); |
| } |
| else { |
| myRefreshIcon.suspend(); |
| } |
| myRefreshIcon.revalidate(); |
| myRefreshIcon.repaint(); |
| } |
| }, visible ? 100 : 300); |
| } |
| }); |
| } |
| |
| public void setRefreshToolTipText(final String tooltip) { |
| myRefreshIcon.setToolTipText(tooltip); |
| } |
| |
| public BalloonHandler notifyByBalloon(MessageType type, String htmlBody, @Nullable Icon icon, @Nullable HyperlinkListener listener) { |
| final Balloon balloon = JBPopupFactory.getInstance().createHtmlTextBalloonBuilder( |
| htmlBody.replace("\n", "<br>"), |
| icon != null ? icon : type.getDefaultIcon(), |
| type.getPopupBackground(), |
| listener).createBalloon(); |
| |
| SwingUtilities.invokeLater(new Runnable() { |
| @Override |
| public void run() { |
| Component comp = InfoAndProgressPanel.this; |
| if (comp.isShowing()) { |
| int offset = comp.getHeight() / 2; |
| Point point = new Point(comp.getWidth() - offset, comp.getHeight() - offset); |
| balloon.show(new RelativePoint(comp, point), Balloon.Position.above); |
| } else { |
| final JRootPane rootPane = SwingUtilities.getRootPane(comp); |
| if (rootPane != null && rootPane.isShowing()) { |
| final Container contentPane = rootPane.getContentPane(); |
| final Rectangle bounds = contentPane.getBounds(); |
| final Point target = UIUtil.getCenterPoint(bounds, new Dimension(1, 1)); |
| target.y = bounds.height - 3; |
| balloon.show(new RelativePoint(contentPane, target), Balloon.Position.above); |
| } |
| } |
| } |
| }); |
| |
| return new BalloonHandler() { |
| @Override |
| public void hide() { |
| SwingUtilities.invokeLater(new Runnable() { |
| @Override |
| public void run() { |
| balloon.hide(); |
| } |
| }); |
| } |
| }; |
| } |
| |
| private static class InlineLayout extends AbstractLayoutManager { |
| private int myProgressWidth; |
| |
| @Override |
| public Dimension preferredLayoutSize(final Container parent) { |
| Dimension result = new Dimension(); |
| for (int i = 0; i < parent.getComponentCount(); i++) { |
| final Dimension prefSize = parent.getComponent(i).getPreferredSize(); |
| result.width += prefSize.width; |
| result.height = Math.max(prefSize.height, result.height); |
| } |
| return result; |
| } |
| |
| @Override |
| public void layoutContainer(final Container parent) { |
| assert parent.getComponentCount() == 2; // 1. info; 2. progress |
| |
| Component infoPanel = parent.getComponent(0); |
| Component progressPanel = parent.getComponent(1); |
| int progressPrefWidth = progressPanel.getPreferredSize().width; |
| |
| final Dimension size = parent.getSize(); |
| int maxProgressWidth = (int) (size.width * 0.8); |
| int minProgressWidth = (int) (size.width * 0.5); |
| if (progressPrefWidth > myProgressWidth) { |
| myProgressWidth = progressPrefWidth; |
| } |
| if (myProgressWidth > maxProgressWidth) { |
| myProgressWidth = maxProgressWidth; |
| } |
| if (myProgressWidth < minProgressWidth) { |
| myProgressWidth = minProgressWidth; |
| } |
| infoPanel.setBounds(0, 0, size.width - myProgressWidth, size.height); |
| progressPanel.setBounds(size.width - myProgressWidth, 0, myProgressWidth, size.height); |
| } |
| } |
| |
| @NotNull |
| private InlineProgressIndicator createInlineDelegate(@NotNull TaskInfo info, @NotNull ProgressIndicatorEx original, final boolean compact) { |
| final Collection<InlineProgressIndicator> inlines = myOriginal2Inlines.get(original); |
| if (inlines != null) { |
| for (InlineProgressIndicator eachInline : inlines) { |
| if (eachInline.isCompact() == compact) return eachInline; |
| } |
| } |
| |
| final InlineProgressIndicator inline = new MyInlineProgressIndicator(compact, info, original); |
| |
| myInline2Original.put(inline, original); |
| myOriginal2Inlines.put(original, inline); |
| |
| if (compact) { |
| inline.getComponent().addMouseListener(new MouseAdapter() { |
| @Override |
| public void mousePressed(MouseEvent e) { |
| handle(e); |
| } |
| |
| @Override |
| public void mouseReleased(MouseEvent e) { |
| handle(e); |
| } |
| }); |
| } |
| |
| return inline; |
| } |
| |
| private void triggerPopupShowing() { |
| if (myPopup.isShowing()) { |
| hideProcessPopup(); |
| } |
| else { |
| openProcessPopup(true); |
| } |
| } |
| |
| private void restoreEmptyStatus() { |
| removeAll(); |
| setLayout(new BorderLayout()); |
| add(myRefreshAndInfoPanel, BorderLayout.CENTER); |
| |
| myProgressIcon.suspend(); |
| myRefreshAndInfoPanel.revalidate(); |
| myRefreshAndInfoPanel.repaint(); |
| } |
| |
| //private String formatTime(long t) { |
| // if (t < 1000) return "< 1 sec"; |
| // if (t < 60 * 1000) return (t / 1000) + " sec"; |
| // return "~" + (int)Math.ceil(t / (60 * 1000f)) + " min"; |
| //} |
| |
| public boolean isProcessWindowOpen() { |
| return myPopup.isShowing(); |
| } |
| |
| public void setProcessWindowOpen(final boolean open) { |
| if (open) { |
| openProcessPopup(true); |
| } |
| else { |
| hideProcessPopup(); |
| } |
| } |
| |
| private class MyInlineProgressIndicator extends InlineProgressIndicator { |
| private ProgressIndicatorEx myOriginal; |
| |
| public MyInlineProgressIndicator(final boolean compact, @NotNull TaskInfo task, @NotNull ProgressIndicatorEx original) { |
| super(compact, task); |
| myOriginal = original; |
| original.addStateDelegate(this); |
| } |
| |
| @Override |
| public void cancel() { |
| super.cancel(); |
| updateProgress(); |
| } |
| |
| @Override |
| public void stop() { |
| super.stop(); |
| updateProgress(); |
| } |
| |
| @Override |
| protected boolean isFinished() { |
| TaskInfo info = getInfo(); |
| return info == null || isFinished(info); |
| } |
| |
| @Override |
| public void finish(@NotNull final TaskInfo task) { |
| super.finish(task); |
| queueRunningUpdate(new Runnable() { |
| @Override |
| public void run() { |
| removeProgress(MyInlineProgressIndicator.this); |
| Disposer.dispose(MyInlineProgressIndicator.this); |
| } |
| }); |
| } |
| |
| @Override |
| public void dispose() { |
| super.dispose(); |
| myOriginal = null; |
| } |
| |
| @Override |
| protected void cancelRequest() { |
| myOriginal.cancel(); |
| } |
| |
| @Override |
| protected void queueProgressUpdate(final Runnable update) { |
| myUpdateQueue.queue(new Update(MyInlineProgressIndicator.this, false, 1) { |
| @Override |
| public void run() { |
| update.run(); |
| } |
| }); |
| } |
| |
| @Override |
| protected void queueRunningUpdate(final Runnable update) { |
| myUpdateQueue.queue(new Update(new Object(), false, 0) { |
| @Override |
| public void run() { |
| ApplicationManager.getApplication().invokeLater(update); |
| } |
| }); |
| } |
| } |
| |
| private void runQuery() { |
| if (getRootPane() == null) return; |
| |
| Set<InlineProgressIndicator> indicators = getCurrentInlineIndicators(); |
| if (indicators.isEmpty()) return; |
| |
| for (InlineProgressIndicator each : indicators) { |
| each.updateProgress(); |
| } |
| myQueryAlarm.cancelAllRequests(); |
| myQueryAlarm.addRequest(new Runnable() { |
| @Override |
| public void run() { |
| runQuery(); |
| } |
| }, 2000); |
| } |
| |
| @NotNull |
| private Set<InlineProgressIndicator> getCurrentInlineIndicators() { |
| synchronized (myOriginals) { |
| return myInline2Original.keySet(); |
| } |
| } |
| } |