IDEA-192417 Provide an API for adding status bar widgets

review: IDEA-CR-32748
This commit is contained in:
Anton Lobov
2018-05-22 16:20:56 +02:00
parent caedcd74aa
commit 9e05814128
11 changed files with 106 additions and 34 deletions
@@ -19,6 +19,7 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.Topic;
import org.jetbrains.annotations.NotNull;
@@ -95,4 +96,24 @@ public interface StatusBar extends StatusBarInfo, Disposable {
IdeFrame getFrame();
void install(IdeFrame frame);
class Anchors {
public static final String DEFAULT_ANCHOR = after(SystemInfo.isMac
? StandardWidgets.ENCODING_PANEL
: StandardWidgets.INSERT_OVERWRITE_PANEL);
public static String before(String widgetId) {
return "before " + widgetId;
}
public static String after(String widgetId) {
return "after " + widgetId;
}
}
class StandardWidgets {
public static final String ENCODING_PANEL = "Encoding";
public static final String INSERT_OVERWRITE_PANEL = "InsertOverwrite";
public static final String READONLY_ATTRIBUTE_PANEL = "ReadOnlyAttribute";
public static final String POSITION_PANEL = "Position";
}
}
@@ -0,0 +1,36 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.wm;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Extension point to assist with adding new status bar widgets
*/
public interface StatusBarWidgetProvider {
ExtensionPointName<StatusBarWidgetProvider> EP_NAME = new ExtensionPointName<>("com.intellij.statusBarWidgetProvider");
/**
* Returns a widget to be added to the status bar.
* Returning null means that no widget should be added.
*
* Normally you should return a new instance of your widget here.
* @param project Current project
* @return Widget or null
*/
@Nullable
StatusBarWidget getWidget(@NotNull Project project);
/**
* Determines position of the added widget in relation to other widgets on the status bar.
*
* Utility methods from StatusBar.Anchors can be used to create an anchor with 'before' or 'after' rules.
* Take a look at StatusBar.StandardWidgets if you need to position your widget relatively to one of the standard widgets.
*/
@NotNull
default String getAnchor() {
return StatusBar.Anchors.DEFAULT_ANCHOR;
}
}
@@ -41,6 +41,7 @@ import com.intellij.openapi.wm.impl.status.*;
import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame;
import com.intellij.ui.*;
import com.intellij.ui.mac.MacMainFrameDecorator;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.accessibility.AccessibleContextAccessor;
@@ -56,6 +57,7 @@ import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.lang.reflect.Field;
import java.util.Set;
/**
* @author Anton Katilin
@@ -438,34 +440,36 @@ public class IdeFrameImpl extends JFrame implements IdeFrameEx, AccessibleContex
}
}
private final Set<String> widgetIDs = ContainerUtil.newHashSet();
private void addWidget(StatusBar statusBar, StatusBarWidget widget, String anchor) {
if (!widgetIDs.add(widget.ID())) {
LOG.error("Attempting to add more than one widget with ID: " + widget.ID());
return;
}
statusBar.addWidget(widget, anchor);
}
private void installDefaultProjectStatusBarWidgets(@NotNull final Project project) {
final StatusBar statusBar = getStatusBar();
addWidget(statusBar, new PositionPanel(project), StatusBar.Anchors.before(IdeMessagePanel.FATAL_ERROR));
addWidget(statusBar, new IdeNotificationArea(), StatusBar.Anchors.before(IdeMessagePanel.FATAL_ERROR));
addWidget(statusBar, new EncodingPanel(project), StatusBar.Anchors.after(StatusBar.StandardWidgets.POSITION_PANEL));
addWidget(statusBar, new LineSeparatorPanel(project), StatusBar.Anchors.before(StatusBar.StandardWidgets.ENCODING_PANEL));
addWidget(statusBar, new InsertOverwritePanel(project), StatusBar.Anchors.after(StatusBar.StandardWidgets.ENCODING_PANEL));
addWidget(statusBar, new ToggleReadOnlyAttributePanel(project),
StatusBar.Anchors.after(StatusBar.StandardWidgets.INSERT_OVERWRITE_PANEL));
final PositionPanel positionPanel = new PositionPanel(project);
statusBar.addWidget(positionPanel, "before " + IdeMessagePanel.FATAL_ERROR);
final IdeNotificationArea notificationArea = new IdeNotificationArea();
statusBar.addWidget(notificationArea, "before " + IdeMessagePanel.FATAL_ERROR);
final EncodingPanel encodingPanel = new EncodingPanel(project);
statusBar.addWidget(encodingPanel, "after Position");
final LineSeparatorPanel lineSeparatorPanel = new LineSeparatorPanel(project);
statusBar.addWidget(lineSeparatorPanel, "before " + encodingPanel.ID());
final ToggleReadOnlyAttributePanel readOnlyAttributePanel = new ToggleReadOnlyAttributePanel(project);
final InsertOverwritePanel insertOverwritePanel = new InsertOverwritePanel(project);
statusBar.addWidget(insertOverwritePanel, "after Encoding");
statusBar.addWidget(readOnlyAttributePanel, "after InsertOverwrite");
for (StatusBarWidgetProvider widgetProvider: StatusBarWidgetProvider.EP_NAME.getExtensions()) {
StatusBarWidget widget = widgetProvider.getWidget(project);
if (widget == null) continue;
addWidget(statusBar, widget, widgetProvider.getAnchor());
}
Disposer.register(project, () -> {
statusBar.removeWidget(encodingPanel.ID());
statusBar.removeWidget(lineSeparatorPanel.ID());
statusBar.removeWidget(positionPanel.ID());
statusBar.removeWidget(notificationArea.ID());
statusBar.removeWidget(readOnlyAttributePanel.ID());
statusBar.removeWidget(insertOverwritePanel.ID());
for (String widgetID: widgetIDs) {
statusBar.removeWidget(widgetID);
}
widgetIDs.clear();
//noinspection deprecation
((StatusBarEx)statusBar).removeCustomIndicationComponents();
@@ -263,12 +263,12 @@ public class IdeRootPane extends JRootPane implements UISettingsListener, Dispos
public void dispose() {
componentFactory.disposeComponent(myStatusBar, c);
}
}, "before " + MemoryUsagePanel.WIDGET_ID);
}, StatusBar.Anchors.before(MemoryUsagePanel.WIDGET_ID));
}
}
myStatusBar.addWidget(myMemoryWidget);
myStatusBar.addWidget(new IdeMessagePanel(frame, MessagePool.getInstance()), "before " + MemoryUsagePanel.WIDGET_ID);
myStatusBar.addWidget(new IdeMessagePanel(frame, MessagePool.getInstance()), StatusBar.Anchors.before(MemoryUsagePanel.WIDGET_ID));
setMemoryIndicatorVisible(UISettings.getInstance().getShowMemoryIndicator());
}
@@ -204,6 +204,12 @@ public abstract class EditorBasedStatusBarPopup extends EditorBasedWidget implem
}
protected static class WidgetState {
public static final WidgetState HIDDEN = new WidgetState("", "", false);
static {
HIDDEN.setHidden(true);
}
protected WidgetState(String toolTip, String text, boolean actionEnabled) {
this.toolTip = toolTip;
this.text = text;
@@ -17,6 +17,7 @@ import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.openapi.vfs.encoding.EncodingManagerImpl;
import com.intellij.openapi.vfs.encoding.EncodingUtil;
import com.intellij.openapi.vfs.impl.BulkVirtualFileListenerAdapter;
import com.intellij.openapi.wm.StatusBar;
import com.intellij.openapi.wm.StatusBarWidget;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
@@ -32,8 +33,9 @@ public class EncodingPanel extends EditorBasedStatusBarPopup {
@NotNull
@Override
protected WidgetState getWidgetState(@Nullable VirtualFile file) {
// this is done to preserve the old behavior; not sure if it is correct
if (file == null) return new WidgetState("", "", false);
if (file == null) {
return WidgetState.HIDDEN;
}
Pair<Charset, String> check = EncodingUtil.getCharsetAndTheReasonTooltip(file);
String failReason = check == null ? null : check.second;
@@ -78,6 +80,6 @@ public class EncodingPanel extends EditorBasedStatusBarPopup {
@Override
@NotNull
public String ID() {
return "Encoding";
return StatusBar.StandardWidgets.ENCODING_PANEL;
}
}
@@ -50,7 +50,7 @@ public class InsertOverwritePanel extends EditorBasedWidget implements StatusBar
@Override
@NotNull
public String ID() {
return "InsertOverwrite";
return StatusBar.StandardWidgets.INSERT_OVERWRITE_PANEL;
}
@Override
@@ -24,7 +24,10 @@ public class LineSeparatorPanel extends EditorBasedStatusBarPopup {
@NotNull
@Override
protected WidgetState getWidgetState(@Nullable VirtualFile file) {
String lineSeparator = file == null ? null : LoadTextUtil.detectLineSeparator(file, true);
if (file == null) {
return WidgetState.HIDDEN;
}
String lineSeparator = LoadTextUtil.detectLineSeparator(file, true);
String toolTipText;
String panelText;
if (lineSeparator != null) {
@@ -33,7 +36,7 @@ public class LineSeparatorPanel extends EditorBasedStatusBarPopup {
}
else {
toolTipText = "No line separator";
panelText = file != null ? "n/a" : "";
panelText = "n/a";
}
return new WidgetState(toolTipText, panelText, lineSeparator != null);
@@ -48,7 +48,6 @@ public class PositionPanel extends EditorBasedWidget
public static final String SPACE = " ";
public static final String SEPARATOR = ":";
public static final String MAX_POSSIBLE_TEXT = "0000000000000";
public static final String ID = "Position";
private static final int CHAR_COUNT_SYNC_LIMIT = 500_000;
private static final String CHAR_COUNT_UNKNOWN = "...";
@@ -71,7 +70,7 @@ public class PositionPanel extends EditorBasedWidget
@Override
@NotNull
public String ID() {
return ID;
return StatusBar.StandardWidgets.POSITION_PANEL;
}
@Override
@@ -60,7 +60,7 @@ public class ToggleReadOnlyAttributePanel implements StatusBarWidget.Multiframe,
@Override
@NotNull
public String ID() {
return "ReadOnlyAttribute";
return StatusBar.StandardWidgets.READONLY_ATTRIBUTE_PANEL;
}
@Override
@@ -181,6 +181,7 @@
</extensionPoint>
<extensionPoint name="statusBarComponent" interface="com.intellij.openapi.wm.StatusBarCustomComponentFactory"/>
<extensionPoint name="statusBarWidgetProvider" interface="com.intellij.openapi.wm.StatusBarWidgetProvider"/>
<extensionPoint name="checkinHandlerFactory" interface="com.intellij.openapi.vcs.checkin.CheckinHandlerFactory"/>