/*
* Copyright 2003-2016 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 jetbrains.mps.ide.ui.dialogs.properties.choosers;
import com.intellij.ide.util.gotoByName.ChooseByNameModel;
import com.intellij.ide.util.gotoByName.ChooseByNamePopupComponent.MultiElementsCallback;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.DumbService.DumbModeListener;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.messages.MessageBusConnection;
import jetbrains.mps.workbench.goTo.ui.ChooseByNamePanel;
import jetbrains.mps.workbench.goTo.ui.MpsPopupFactory;
import org.jetbrains.annotations.NotNull;
import javax.swing.JComponent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
final class ChooserDialog<T> extends DialogWrapper {
protected final ChooseByNamePanel myChooser;
protected final ChooseByNameModel myData;
protected boolean myIsCancelled = true;
protected boolean myOkDone = false;
protected final Project myProject;
private List<Object> mySelectedElements;
ChooserDialog(Project project, @NotNull ChooseByNameModel data, boolean hasExtraScope, boolean multiSelection) {
super(project);
myProject = project;
myData = data;
// I have no idea why we call addNotify() here
getContentPane().addNotify();
setModal(true);
myChooser = MpsPopupFactory.createPanelForPackage(project, data, hasExtraScope);
// Although it's odd to have invoke() in the cons, we shall invoke it prior to super.init() otherwise there's no panel in the dialog
myChooser.invoke(new MultiElementsCallback() {
@Override
public void elementsChosen(List<Object> elements) {
if (!myOkDone) {
// I've got no idea why do we guard with this flag, and what's use of its protected visibility
myOkDone = true;
mySelectedElements = elements;
myIsCancelled = false;
// according to ChooseByNamePopup, elementsChosen are invoked when selection
// has to be processed (it was hard to express this contract in the method javadoc, one has to guess it from sources)
// not when actual selection changes (i.e. on double click rather than on single click). As there's nothing else to do in
// this dialog once element is picked, we close it.
ChooserDialog.this.close(OK_EXIT_CODE);
}
}
}, ModalityState.stateForComponent(getWindow()), multiSelection);
Disposer.register(getDisposable(), myChooser);
MessageBusConnection connection = project.getMessageBus().connect();
Disposer.register(getDisposable(), connection);
Runnable reactToDumbMode = () -> ChooserDialog.this.setErrorText("List of elements can be incomplete or empty while indexing is in progress");
connection.subscribe(DumbService.DUMB_MODE, new DumbModeListener() {
@Override
public void enteredDumbMode() {
reactToDumbMode.run();
}
@Override
public void exitDumbMode() {
ChooserDialog.this.setErrorText(null);
}
});
// Can open dialog, while in dumb mode, so need additional check after subscribe to events.
if (DumbService.isDumb(myProject)) {
reactToDumbMode.run();
}
init();
}
/*
* handle Ok dialog button. myChooser doesn't send out events when selection changes,
* only when user double-clicks on an item. We need to handle scenario when user selects an element
* and press 'Ok', that's why we consult chooser for selected elements here instead of using mySelectedElements value.
*/
@Override
protected void doOKAction() {
myIsCancelled = false;
mySelectedElements = myChooser.getChosenElements();
super.doOKAction();
}
@NotNull
public List<T> getResult() {
if (myIsCancelled || mySelectedElements == null) {
return Collections.emptyList();
}
List<T> result = new ArrayList<T>();
for (Object item : mySelectedElements) {
if (item != null) {
@SuppressWarnings("unchecked")
T v = (T) item;
result.add(v);
}
}
return result;
}
@Override
protected JComponent createCenterPanel() {
return myChooser.getPanel();
}
@Override
protected String getDimensionServiceKey() {
return ChooserDialog.class.getCanonicalName();
}
@Override
protected void dispose() {
// I have no idea why we call dispose() here
getContentPane().removeNotify();
super.dispose();
}
@Override
public JComponent getPreferredFocusedComponent() {
return myChooser.getPreferredFocusedComponent();
}
}