/* * 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(); } }