Closed beansoft closed 3 years ago
I've using similar code in mine React Native plugin to update iOS simulator list, so I encounter same issue in 2021 EAP, my temp fix is like this:
Still not sure the reason why this fails since the "Trying to reset custom component in a presentation" error check in Presentation.java is not changed long time.
Below is just for demonstrate for what's i'm doing, please using your own latest code:
public class DeviceSelectorAction extends ComboBoxAction implements DumbAware {
private final List<AnAction> actions = new ArrayList<>();
private final List<Project> knownProjects = Collections.synchronizedList(new ArrayList<>());
private SelectDeviceAction selectedDeviceAction;
public DeviceSelectorAction() {
setSmallVariant(true);
}
@NotNull
@Override
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
final DefaultActionGroup group = new DefaultActionGroup();
group.addAll(actions);
return group;
}
@Override
protected boolean shouldShowDisabledActions() {
return true;
}
@Override
public void update(final AnActionEvent e) {
//// Suppress device actions in all but the toolbars.
//final String place = e.getPlace();
//if (!Objects.equals(place, ActionPlaces.NAVIGATION_BAR_TOOLBAR) && !Objects.equals(place, ActionPlaces.MAIN_TOOLBAR)) {
// e.getPresentation().setVisible(false);
// return;
//}
// Only show device menu when the device daemon process is running.
final Project project = e.getProject();
if (!isSelectorVisible(project)) {
e.getPresentation().setVisible(false);
return;
}
super.update(e);
if (!knownProjects.contains(project)) {
knownProjects.add(project);
Disposer.register(project, () -> knownProjects.remove(project));
DeviceService.getInstance(project).addListener(() -> update(project, e.getPresentation()));
// Listen for android device changes, and rebuild the menu if necessary.
AndroidEmulatorManager.getInstance(project).addListener(() -> update(project, e.getPresentation()));
update(project, e.getPresentation());
}
final DeviceService deviceService = DeviceService.getInstance(project);
final FlutterDevice selectedDevice = deviceService.getSelectedDevice();
final Collection<FlutterDevice> devices = deviceService.getConnectedDevices();
Presentation presentation = e.getPresentation();
final boolean visible = isSelectorVisible(project);
presentation.setVisible(visible);
if (devices.isEmpty()) {
final boolean isLoading = deviceService.getStatus() == DeviceService.State.LOADING;
if (isLoading) {
presentation.setText(FlutterBundle.message("devicelist.loading"));
}
else {
//noinspection DialogTitleCapitalization
presentation.setText("<no devices>");
}
}
else if (selectedDevice == null) {
//noinspection DialogTitleCapitalization
presentation.setText("<no device selected>");
} else if(selectedDeviceAction != null) {
final Presentation template = selectedDeviceAction.getTemplatePresentation();
presentation.setIcon(template.getIcon());
presentation.setText(selectedDevice.presentationName());
presentation.setEnabled(true);
}
}
private void update(Project project, Presentation presentation) {
FlutterUtils.invokeAndWait(() -> {
updateActions(project, presentation);
updateVisibility(project, presentation);
});
}
private static void updateVisibility(final Project project, final Presentation presentation) {
final boolean visible = isSelectorVisible(project);
//presentation.setVisible(visible);
final JComponent component = (JComponent)presentation.getClientProperty("customComponent");
if (component != null) {
component.setVisible(visible);
if (component.getParent() != null) {
component.getParent().doLayout();
component.getParent().repaint();
}
}
}
private static boolean isSelectorVisible(@Nullable Project project) {
return project != null &&
DeviceService.getInstance(project).getStatus() != DeviceService.State.INACTIVE &&
FlutterModuleUtils.hasFlutterModule(project);
}
private void updateActions(@NotNull Project project, Presentation presentation) {
actions.clear();
final DeviceService deviceService = DeviceService.getInstance(project);
final FlutterDevice selectedDevice = deviceService.getSelectedDevice();
final Collection<FlutterDevice> devices = deviceService.getConnectedDevices();
selectedDeviceAction = null;
for (FlutterDevice device : devices) {
final SelectDeviceAction deviceAction = new SelectDeviceAction(device, devices);
actions.add(deviceAction);
if (Objects.equals(device, selectedDevice)) {
selectedDeviceAction = deviceAction;
}
}
// Show the 'Open iOS Simulator' action.
if (SystemInfo.isMac) {
boolean simulatorOpen = false;
for (AnAction action : actions) {
if (action instanceof SelectDeviceAction) {
final SelectDeviceAction deviceAction = (SelectDeviceAction)action;
final FlutterDevice device = deviceAction.device;
if (device.isIOS() && device.emulator()) {
simulatorOpen = true;
}
}
}
actions.add(new Separator());
actions.add(new OpenSimulatorAction(!simulatorOpen));
actions.add(new RefreshDeviceAction());
}
// Add Open Android emulators actions.
final List<OpenEmulatorAction> emulatorActions = OpenEmulatorAction.getEmulatorActions(project);
if (!emulatorActions.isEmpty()) {
actions.add(new Separator());
actions.addAll(emulatorActions);
}
// Notify the IDE system to update AnAction
ActivityTracker.getInstance().inc();
}
// Show the current device as selected when the combo box menu opens.
@Override
protected Condition<AnAction> getPreselectCondition() {
return action -> action == selectedDeviceAction;
}
private static class SelectDeviceAction extends AnAction {
@NotNull
private final FlutterDevice device;
SelectDeviceAction(@NotNull FlutterDevice device, @NotNull Collection<FlutterDevice> devices) {
super(device.getUniqueName(devices), null, FlutterIcons.Phone);
this.device = device;
}
public String presentationName() {
return device.presentationName();
}
@Override
public void actionPerformed(AnActionEvent e) {
final Project project = e.getProject();
final DeviceService service = project == null ? null : DeviceService.getInstance(project);
if (service != null) {
service.setSelectedDevice(device);
}
}
}
}
Trying to reset custom component in a presentation
java.lang.Throwable at com.intellij.openapi.actionSystem.Presentation.putClientProperty(Presentation.java:403) at com.intellij.openapi.actionSystem.Presentation.copyFrom(Presentation.java:376) at com.intellij.openapi.actionSystem.impl.ActionUpdater.lambda$reflectSubsequentChangesInOriginalPresentation$9(ActionUpdater.java:131) at java.desktop/java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:341) at java.desktop/java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:333) at java.desktop/java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:266) at com.intellij.openapi.actionSystem.Presentation.fireObjectPropertyChange(Presentation.java:342) at com.intellij.openapi.actionSystem.Presentation.setTextWithMnemonic(Presentation.java:190) at com.intellij.openapi.actionSystem.Presentation.setText(Presentation.java:145) at com.intellij.openapi.actionSystem.Presentation.setText(Presentation.java:200) at io.flutter.actions.DeviceSelectorAction.updateActions(DeviceSelectorAction.java:165)