blob: 9f28f8868ae791caf136d26825dbf9331c585ad9 [file] [log] [blame]
package com.intellij.tasks.impl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.List;
/**
* @author Mikhail Golubev
*/
public class TaskUiUtil {
private static Logger LOG = Logger.getInstance(TaskUiUtil.class);
private TaskUiUtil() {
// Utility class
}
/**
* Special kind of backgroundable task tailored to update UI in modal dialogs, which is very common for
* task repository editors in settings.
*/
public abstract static class RemoteFetchTask<T> extends Task.Backgroundable {
protected T myResult;
protected Exception myException;
private final ModalityState myModalityState = ModalityState.current();
/**
* Should be called only from EDT, so current modality state can be captured.
*/
protected RemoteFetchTask(@Nullable Project project, @NotNull String title) {
super(project, title);
}
@Override
public final void run(@NotNull ProgressIndicator indicator) {
try {
myResult = fetch(indicator);
}
catch (Exception e) {
LOG.error(e);
myException = e;
}
}
/**
* {@link #onSuccess()} can't be used for this purpose, because it doesn't consider current modality state
* which will prevent UI updating in modal dialog (e.g. in {@link com.intellij.tasks.config.TaskRepositoryEditor}).
* @return
*/
@Nullable
@Override
public final NotificationInfo notifyFinished() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
updateUI();
}
}, myModalityState);
return null;
}
@NotNull
protected abstract T fetch(@NotNull ProgressIndicator indicator) throws Exception;
protected abstract void updateUI();
}
/**
* Auxiliary remote fetcher designed to simplify updating of combo boxes in repository editors, which is
* indeed a rather common task.
*/
public static abstract class ComboBoxUpdater<T> extends RemoteFetchTask<List<T>> {
protected final ComboBox myComboBox;
public ComboBoxUpdater(@Nullable Project project, @NotNull String title, @NotNull ComboBox comboBox) {
super(project, title);
myComboBox = comboBox;
}
/**
* Return extra item like "All projects", which will be added as first item after every combo box update.
*
* @return extra first combo box item
*/
@Nullable
public T getExtraItem() {
return null;
}
/**
* Return item to select after every combo box update. Default implementation select item, returned by {@link #getExtraItem()}.
*
* @return selected combo box item
*/
@Nullable
public T getSelectedItem() {
return getExtraItem();
}
@SuppressWarnings("unchecked")
@Override
protected void updateUI() {
if (myResult != null) {
myComboBox.setModel(new DefaultComboBoxModel(ArrayUtil.toObjectArray(myResult)));
T extra = getExtraItem();
if (extra != null) {
myComboBox.insertItemAt(extra, 0);
}
// ensure that selected ItemEvent will be fired, even if first item of the model
// is the same as the next selected
myComboBox.setSelectedItem(null);
T selected = getSelectedItem();
if (selected != null) {
myComboBox.setSelectedItem(selected);
}
else if (myComboBox.getItemCount() > 0) {
myComboBox.setSelectedIndex(0);
}
}
else {
// Some error occurred
handleError();
}
}
protected void handleError() {
myComboBox.removeAllItems();
}
}
/**
* Very simple wrapper around {@link com.intellij.ui.ListCellRendererWrapper} useful for
* combo boxes where each item has plain text representation with special message for
* {@code null} value.
*/
public static class SimpleComboBoxRenderer<T> extends ListCellRendererWrapper<T> {
private final String myNullDescription;
public SimpleComboBoxRenderer(@NotNull String nullDescription) {
myNullDescription = nullDescription;
}
@Override
public final void customize(JList list, T value, int index, boolean selected, boolean hasFocus) {
setText(value == null ? myNullDescription : getDescription(value));
}
@NotNull
protected String getDescription(@NotNull T item) {
return item.toString();
}
}
}