/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.ide.navigation; import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.Style; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.logical.shared.ResizeEvent; import com.google.gwt.event.logical.shared.ResizeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; import com.google.inject.Inject; import com.google.inject.Singleton; import elemental.dom.Element; import elemental.html.TableCellElement; import elemental.html.TableElement; import org.eclipse.che.api.project.shared.dto.ItemReference; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.Resources; import org.eclipse.che.ide.api.autocomplete.AutoCompleteResources; import org.eclipse.che.ide.resource.Path; import org.eclipse.che.ide.ui.list.SimpleList; import org.eclipse.che.ide.util.dom.Elements; import java.util.List; /** * The implementation of {@link NavigateToFileView} view. * * @author Ann Shumilova * @author Artem Zatsarynnyi * @author Vlad Zhukovskyi */ @Singleton public class NavigateToFileViewImpl extends PopupPanel implements NavigateToFileView { interface NavigateToFileViewImplUiBinder extends UiBinder<Widget, NavigateToFileViewImpl> { } @UiField TextBox fileName; @UiField(provided = true) CoreLocalizationConstant locale; private ActionDelegate delegate; private final AutoCompleteResources.Css css; private final Resources resources; private SimpleList<ItemReference> list; @UiField FlowPanel suggestionsPanel; @UiField HTML suggestionsContainer; private HandlerRegistration resizeHandler; @Inject public NavigateToFileViewImpl(CoreLocalizationConstant locale, NavigateToFileViewImplUiBinder uiBinder, AutoCompleteResources autoCompleteResources, Resources resources) { this.locale = locale; this.resources = resources; css = autoCompleteResources.autocompleteComponentCss(); css.ensureInjected(); setWidget(uiBinder.createAndBindUi(this)); setAutoHideEnabled(true); setAnimationEnabled(true); getElement().getStyle().setProperty("boxShadow", "0 2px 4px 0 rgba(0, 0, 0, 0.50)"); getElement().getStyle().setProperty("borderRadius", "0px"); } @Override public void setDelegate(ActionDelegate delegate) { this.delegate = delegate; } @Override public void showPopup() { fileName.getElement().setAttribute("placeholder", locale.navigateToFileSearchIsCaseSensitive()); setPopupPositionAndShow(new PositionCallback() { @Override public void setPosition(int offsetWidth, int offsetHeight) { setPopupPosition((com.google.gwt.user.client.Window.getClientWidth() / 2) - (offsetWidth / 2), (com.google.gwt.user.client.Window.getClientHeight() / 4) - (offsetHeight / 2)); // Set 'clip' css property to auto when show animation is finished. new Timer() { @Override public void run() { getElement().getStyle().setProperty("clip", "auto"); delegate.onFileNameChanged(fileName.getText()); } }.schedule(300); } }); Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { fileName.setFocus(true); } }); // Add window resize handler if (resizeHandler == null) { resizeHandler = Window.addResizeHandler(new ResizeHandler() { @Override public void onResize(ResizeEvent event) { updatePositionAndSize(); } }); } } private final SimpleList.ListItemRenderer<ItemReference> listItemRenderer = new SimpleList.ListItemRenderer<ItemReference>() { @Override public void render(Element itemElement, ItemReference itemData) { TableCellElement label = Elements.createTDElement(); TableCellElement path = Elements.createTDElement(); Path itemPath = Path.valueOf(itemData.getPath()); label.setInnerHTML(itemPath.lastSegment()); path.setInnerHTML("(" + itemPath.parent() + ")"); itemElement.appendChild(label); itemElement.appendChild(path); path.getStyle().setProperty("opacity", "0.6"); } @Override public Element createElement() { return Elements.createTRElement(); } }; @Override public void hidePopup() { suggestionsContainer.getElement().setInnerHTML(""); suggestionsPanel.setVisible(false); suggestionsPanel.getElement().getStyle().setWidth(400, Style.Unit.PX); suggestionsPanel.getElement().getStyle().setHeight(20, Style.Unit.PX); if (resizeHandler != null) { resizeHandler.removeHandler(); resizeHandler = null; } super.hide(); } @Override public void showItems(List<ItemReference> items) { // Hide popup if it is nothing to show if (items.isEmpty()) { suggestionsContainer.getElement().setInnerHTML(""); suggestionsPanel.setVisible(false); suggestionsPanel.getElement().getStyle().setWidth(400, Style.Unit.PX); suggestionsPanel.getElement().getStyle().setHeight(20, Style.Unit.PX); return; } // Show popup suggestionsPanel.setVisible(true); suggestionsContainer.getElement().setInnerHTML(""); // Create and show list of items final TableElement itemHolder = Elements.createTableElement(); suggestionsContainer.getElement().appendChild(((com.google.gwt.dom.client.Element) itemHolder)); list = SimpleList.create((SimpleList.View) suggestionsContainer.getElement().cast(), (Element)suggestionsContainer.getElement(), itemHolder, resources.defaultSimpleListCss(), listItemRenderer, eventDelegate); list.render(items); list.getSelectionModel().setSelectedItem(0); // Update popup position updatePositionAndSize(); } private void updatePositionAndSize() { // Update position setPopupPosition((com.google.gwt.user.client.Window.getClientWidth() / 2) - (getOffsetWidth() / 2), (com.google.gwt.user.client.Window.getClientHeight() / 4) - (getOffsetHeight() / 2)); // Exit if suggestions is not shown if (!suggestionsPanel.isVisible()) { return; } // Update popup width int width = suggestionsContainer.getElement().getFirstChildElement().getOffsetWidth(); int newWidth = Window.getClientWidth() - getElement().getAbsoluteLeft() - 50; if (width < newWidth) { newWidth = width; } suggestionsPanel.getElement().getStyle().setWidth(newWidth, Style.Unit.PX); // Update popup height int height = suggestionsContainer.getElement().getFirstChildElement().getOffsetHeight(); int newHeight = height > 300 ? 300 : height; int bottom = getElement().getAbsoluteTop() + getElement().getOffsetHeight(); if (bottom + newHeight > Window.getClientHeight() - 10) { newHeight = Window.getClientHeight() - 10 - bottom; } if (newHeight < 50) { newHeight = 50; } suggestionsPanel.getElement().getStyle().setHeight(newHeight, Style.Unit.PX); } private final SimpleList.ListEventDelegate<ItemReference> eventDelegate = new SimpleList.ListEventDelegate<ItemReference>() { @Override public void onListItemClicked(Element listItemBase, ItemReference itemData) { list.getSelectionModel().setSelectedItem(itemData); } @Override public void onListItemDoubleClicked(Element listItemBase, ItemReference itemData) { delegate.onFileSelected(Path.valueOf(itemData.getPath()));; } }; @UiHandler("fileName") void handleKeyDown(KeyDownEvent event) { switch (event.getNativeKeyCode()) { case KeyCodes.KEY_UP: event.stopPropagation(); event.preventDefault(); if (list != null) { list.getSelectionModel().selectPrevious(); } return; case KeyCodes.KEY_DOWN: event.stopPropagation(); event.preventDefault(); if (list != null) { list.getSelectionModel().selectNext(); } return; case KeyCodes.KEY_PAGEUP: event.stopPropagation(); event.preventDefault(); if (list != null) { list.getSelectionModel().selectPreviousPage(); } return; case KeyCodes.KEY_PAGEDOWN: event.stopPropagation(); event.preventDefault(); if (list != null) { list.getSelectionModel().selectNextPage(); } return; case KeyCodes.KEY_ENTER: event.stopPropagation(); event.preventDefault(); ItemReference selectedItem = list.getSelectionModel().getSelectedItem(); if (selectedItem != null) { delegate.onFileSelected(Path.valueOf(selectedItem.getPath()));; } return; case KeyCodes.KEY_ESCAPE: event.stopPropagation(); event.preventDefault(); hidePopup(); return; } Scheduler.get().scheduleDeferred(new Command() { @Override public void execute() { delegate.onFileNameChanged(fileName.getText()); } }); } }