Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package de.php_perfect.intellij.ddev.statusBar;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.wm.StatusBar;
import com.intellij.openapi.wm.StatusBarWidget;
import com.intellij.openapi.wm.StatusBarWidgetFactory;
import com.intellij.openapi.wm.impl.status.widget.StatusBarEditorBasedWidgetFactory;
import de.php_perfect.intellij.ddev.DdevIntegrationBundle;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

public final class DdevStatusBarWidgetFactoryImpl implements StatusBarWidgetFactory {
public final class DdevStatusBarWidgetFactoryImpl extends StatusBarEditorBasedWidgetFactory {
@Override
public @NonNls @NotNull String getId() {
return DdevStatusBarWidgetImpl.WIDGET_ID;
Expand All @@ -22,22 +21,13 @@ public final class DdevStatusBarWidgetFactoryImpl implements StatusBarWidgetFact
}

@Override
public boolean isAvailable(@NotNull Project project) {
return true;
public boolean canBeEnabledOn(@NotNull StatusBar statusBar) {
Project project = statusBar.getProject();
return project != null;
}

@Override
public @NotNull StatusBarWidget createWidget(@NotNull Project project) {
return new DdevStatusBarWidgetImpl(project);
}

@Override
public void disposeWidget(@NotNull StatusBarWidget widget) {
Disposer.dispose(widget);
}

@Override
public boolean canBeEnabledOn(@NotNull StatusBar statusBar) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
package de.php_perfect.intellij.ddev.statusBar;

import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.wm.CustomStatusBarWidget;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.StatusBar;
import com.intellij.openapi.wm.impl.status.TextPanel;
import com.intellij.ui.ClickListener;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.popup.PopupState;
import com.intellij.openapi.wm.StatusBarWidget;
import com.intellij.openapi.wm.impl.status.EditorBasedStatusBarPopup;
import com.intellij.util.concurrency.EdtExecutorService;
import com.intellij.util.messages.MessageBus;
import de.php_perfect.intellij.ddev.DdevIntegrationBundle;
Expand All @@ -31,24 +27,18 @@
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.concurrent.TimeUnit;

import static com.intellij.util.ui.update.UiNotifyConnector.doWhenFirstShown;

public final class DdevStatusBarWidgetImpl implements CustomStatusBarWidget {
public final class DdevStatusBarWidgetImpl extends EditorBasedStatusBarPopup {
private static final @NotNull Logger LOG = Logger.getInstance(DdevStatusBarWidgetImpl.class);
private static final Key<State> DDEV_STATE_KEY = new Key<>("DdevIntegration.State");
private static final @NotNull String ACTION_GROUP = "DdevIntegration.Services";
public static final @NotNull String WIDGET_ID = DdevStatusBarWidgetImpl.class.getName();
private final @NotNull PopupState<JBPopup> popupState = PopupState.forPopup();
private final @NotNull Project project;
private @Nullable StatusBar statusBar;
private @Nullable TextPanel.WithIconAndArrows component;
private @Nullable ClickListener clickListener = null;
public static final @NotNull String WIDGET_ID = "DdevStatusBarWidget";

public DdevStatusBarWidgetImpl(@NotNull Project project) {
this.project = project;
super(project, false);
}

@Override
Expand All @@ -58,104 +48,73 @@ public DdevStatusBarWidgetImpl(@NotNull Project project) {

@Override
public void install(@NotNull StatusBar statusBar) {
if (statusBar.getProject() != null && !statusBar.getProject().equals(this.project)) {
if (statusBar.getProject() != null && !statusBar.getProject().equals(this.getProject())) {
LOG.warn("Cannot install widget from one project on status bar of another project");
return;
}

this.statusBar = statusBar;
this.clickListener = new ClickListener() {
@Override
public boolean onClick(@NotNull MouseEvent event, int clickCount) {
showPopup(event);
return true;
}
};

super.install(statusBar);
registerUpdateListener();
}

@Override
public JComponent getComponent() {
this.component = new TextPanel.WithIconAndArrows();
this.component.setIcon(DdevIntegrationIcons.DdevLogoMono);
this.component.setToolTipText(DdevIntegrationBundle.message("statusBar.toolTip"));
this.component.setVisible(false);
doWhenFirstShown(this.component, () -> delayTutorial(this.component), this);

return this.component;
}

@Override
public void dispose() {
this.statusBar = null;
doWhenFirstShown(super.getComponent(), () -> delayTutorial(super.getComponent()), this);
}

private void registerUpdateListener() {
MessageBus messageBus = this.project.getMessageBus();
MessageBus messageBus = this.getProject().getMessageBus();
messageBus.connect(this).subscribe(StateChangedListener.DDEV_CHANGED, new StatusBarUpdateListener());
}

private final class StatusBarUpdateListener implements StateChangedListener {
@Override
public void onDdevChanged(@NotNull State state) {
DdevStatusBarWidgetImpl.this.updateComponent(state);
}
}

private void showPopup(@NotNull MouseEvent e) {
if (popupState.isRecentlyHidden()) {
return;
DdevStatusBarWidgetImpl.this.putState(state);
DdevStatusBarWidgetImpl.this.update();
}

DataContext context = DataManager.getInstance().getDataContext((Component) statusBar);
ListPopup popup = createPopup(context);
Disposer.register(this, popup);
Dimension dimension = popup.getContent().getPreferredSize();
Point at = new Point(0, -dimension.height);
popupState.prepareToShow(popup);
popup.show(new RelativePoint(e.getComponent(), at));
Disposer.register(this, popup);
}

private ListPopup createPopup(DataContext context) {
@Override
protected @NotNull ListPopup createPopup(@NotNull DataContext context) {
ActionGroup group = (ActionGroup) ActionManager.getInstance().getAction(ACTION_GROUP);
String place = ActionPlaces.getPopupPlace(ActionPlaces.STATUS_BAR_PLACE);

return JBPopupFactory.getInstance().createActionGroupPopup(null, group, context, JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false, place);
}

private void updateComponent(State state) {
if (this.component == null) {
return;
}

if (!state.isAvailable() || !state.isConfigured()) {
this.component.setVisible(false);
@Override
protected @NotNull StatusBarWidget createInstance(@NotNull Project project) {
return new DdevStatusBarWidgetImpl(project);
}

return;
@Override
protected @NotNull WidgetState getWidgetState(@Nullable VirtualFile file) {
State state = this.fetchState();
if (state == null || !state.isAvailable() || !state.isConfigured()) {
return WidgetState.HIDDEN;
}

this.component.setVisible(true);
this.component.setText(this.getText(state));

if (this.clickListener != null) {
this.clickListener.uninstall(this.component);
}
String toolTipText = DdevIntegrationBundle.message("statusBar.toolTip");
String statusText = this.getStatusText();
WidgetState widgetState = new WidgetState(toolTipText, statusText, true);
widgetState.setIcon(DdevIntegrationIcons.DdevLogoMono);

Description description = state.getDescription();
if (this.clickListener != null && description != null && description.getStatus() == Description.Status.RUNNING) {
this.clickListener.installOn(this.component, true);
}
return widgetState;
}

private void delayTutorial(@NotNull JComponent component) {
EdtExecutorService.getScheduledExecutorInstance().schedule(() -> GotItTutorial.getInstance().showStatusBarTutorial(component, this), 3000, TimeUnit.MILLISECONDS);
EdtExecutorService.getScheduledExecutorInstance().schedule(() -> {
if (!this.isDisposed()) {
GotItTutorial.getInstance().showStatusBarTutorial(component, this);
}
}, 3000, TimeUnit.MILLISECONDS);
}

private @NotNull @NlsContexts.StatusBarText String getText(@NotNull State state) {
Description description = state.getDescription();
private @NotNull @NlsContexts.StatusBarText String getStatusText() {
Description description = null;
Description.Status status = null;
State state = this.fetchState();

if (state != null) {
description = state.getDescription();
}

if (description != null) {
status = description.getStatus();
Expand All @@ -179,4 +138,12 @@ private void delayTutorial(@NotNull JComponent component) {
case UNHEALTHY -> DdevIntegrationBundle.message("status.Unhealthy");
};
}

private void putState(State state) {
this.getProject().putUserData(DDEV_STATE_KEY, state);
}

private State fetchState() {
return this.getProject().getUserData(DDEV_STATE_KEY);
}
}
2 changes: 1 addition & 1 deletion src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@

<statusBarWidgetFactory order="before light.edit.large.file.encoding.widget"
implementation="de.php_perfect.intellij.ddev.statusBar.DdevStatusBarWidgetFactoryImpl"
id="de.php_perfect.ddev.statusBar"/>
id="DdevStatusBarWidget"/>

<statistics.gotItTooltipAllowlist prefix="ddev.features"/>

Expand Down