/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * 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 org.kie.workbench.common.screens.library.client.screens; import java.util.List; import javax.enterprise.event.Event; import javax.enterprise.event.Observes; import javax.inject.Inject; import com.google.gwt.core.client.Scheduler; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.IsWidget; import org.ext.uberfire.social.activities.client.widgets.utils.SocialDateFormatter; import org.jboss.errai.common.client.api.Caller; import org.jboss.errai.common.client.api.RemoteCallback; import org.jboss.errai.ui.client.local.spi.TranslationService; import org.kie.workbench.common.screens.explorer.client.utils.Classifier; import org.kie.workbench.common.screens.explorer.client.utils.Utils; import org.kie.workbench.common.screens.explorer.model.FolderItemType; import org.kie.workbench.common.screens.library.api.AssetInfo; import org.kie.workbench.common.screens.library.api.LibraryService; import org.kie.workbench.common.screens.library.api.ProjectAssetsQuery; import org.kie.workbench.common.screens.library.api.ProjectInfo; import org.kie.workbench.common.screens.library.api.search.FilterUpdateEvent; import org.kie.workbench.common.screens.library.client.events.AssetDetailEvent; import org.kie.workbench.common.screens.library.client.events.ProjectDetailEvent; import org.kie.workbench.common.screens.library.client.perspective.LibraryPerspective; import org.kie.workbench.common.screens.library.client.resources.i18n.LibraryConstants; import org.kie.workbench.common.screens.library.client.util.LibraryPlaces; import org.uberfire.backend.vfs.Path; import org.uberfire.client.annotations.WorkbenchPartTitle; import org.uberfire.client.annotations.WorkbenchPartView; import org.uberfire.client.annotations.WorkbenchScreen; import org.uberfire.client.mvp.UberElement; import org.uberfire.client.workbench.events.PlaceGainFocusEvent; import org.uberfire.client.workbench.type.ClientResourceType; import org.uberfire.ext.widgets.common.client.common.BusyIndicatorView; import org.uberfire.mvp.Command; import org.uberfire.mvp.PlaceRequest; import org.uberfire.util.URIUtil; @WorkbenchScreen(identifier = LibraryPlaces.PROJECT_SCREEN, owningPerspective = LibraryPerspective.class) public class ProjectScreen { private View view; private LibraryPlaces libraryPlaces; private TranslationService ts; private Caller<LibraryService> libraryService; private Classifier assetClassifier; private Event<AssetDetailEvent> assetDetailEvent; private BusyIndicatorView busyIndicatorView; private ProjectInfo projectInfo; private List<AssetInfo> assets; private Reloader reloader = new Reloader(); private Timer projectLoadTimer; private boolean isProjectLoadPending = false; private boolean isProjectLoadInProgress = false; @Inject public ProjectScreen(final View view, final LibraryPlaces libraryPlaces, final TranslationService ts, final Caller<LibraryService> libraryService, final Classifier assetClassifier, final Event<AssetDetailEvent> assetDetailEvent, final BusyIndicatorView busyIndicatorView) { this.view = view; this.libraryPlaces = libraryPlaces; this.ts = ts; this.libraryService = libraryService; this.assetClassifier = assetClassifier; this.assetDetailEvent = assetDetailEvent; this.busyIndicatorView = busyIndicatorView; } public void onStartup(@Observes final ProjectDetailEvent projectDetailEvent) { this.projectInfo = projectDetailEvent.getProjectInfo(); loadProjectInfo(); view.setProjectName(projectInfo.getProject().getProjectName()); } public void refreshOnFocus(@Observes final PlaceGainFocusEvent placeGainFocusEvent) { final PlaceRequest place = placeGainFocusEvent.getPlace(); if (projectInfo != null && place.getIdentifier().equals(LibraryPlaces.PROJECT_SCREEN)) { loadProjectInfo(); } } public void onUpdateAssets() { cancel(); projectLoadTimer = createTimer(); projectLoadTimer.schedule(250); } protected Timer createTimer() { return new Timer() { @Override public void run() { loadProjectInfo(); } }; } private void cancel() { if (projectLoadTimer != null) { projectLoadTimer.cancel(); projectLoadTimer = null; } } public void goToSettings() { assetDetailEvent.fire(new AssetDetailEvent(projectInfo, null)); } public String getProjectName() { return projectInfo.getProject().getProjectName(); } String getLastModifiedTime(final AssetInfo asset) { return ts.format(LibraryConstants.LastModified) + " " + SocialDateFormatter.format(asset.getLastModifiedTime()); } String getCreatedTime(final AssetInfo asset) { return ts.format(LibraryConstants.Created) + " " + SocialDateFormatter.format(asset.getCreatedTime()); } Command selectCommand(final Path assetPath) { return () -> libraryPlaces.goToAsset(projectInfo, assetPath); } Command detailsCommand(final Path assetPath) { return selectCommand(assetPath); } void loadProjectInfo() { if (isProjectLoadInProgress) { isProjectLoadPending = true; return; } busyIndicatorView.showBusyIndicator(ts.getTranslation(LibraryConstants.LoadingAssets)); isProjectLoadInProgress = true; final int firstIndex = getFirstIndex(); libraryService.call(new RemoteCallback<List<AssetInfo>>() { @Override public void callback(List<AssetInfo> assetsList) { assets = assetsList; view.range(firstIndex + 1, firstIndex + assetsList.size()); setupAssets(assets); setupForwardBackwardButtons(firstIndex); busyIndicatorView.hideBusyIndicator(); isProjectLoadInProgress = false; if (isProjectLoadPending) { isProjectLoadPending = false; loadProjectInfo(); } else { reloader.check(assetsList); } } }).getProjectAssets(new ProjectAssetsQuery(projectInfo.getProject(), view.getFilterValue(), firstIndex, view.getStep())); } private void setupForwardBackwardButtons(final int firstIndex) { view.setBackwardDisabled(firstIndex == 0); view.setForwardDisabled(isThereRoomOnThisPage()); } private boolean isThereRoomOnThisPage() { Integer step = view.getStep(); return step > assets.size(); } private int getFirstIndex() { final int step = view.getStep(); final int result = (view.getPageNumber() * step) - step; if (result < 1) { view.setPageNumber(1); return 0; } else { return result; } } private void setupAssets(final List<AssetInfo> assets) { view.clearAssets(); view.hideEmptyState(); if (assets.isEmpty()) { if (isFilterEmpty()) { if (getFirstIndex() == 0) { view.showIndexingIncomplete(); } else { view.showNoMoreAssets(); } } else { if (getFirstIndex() == 0) { view.showSearchHitNothing(); } else { view.showNoMoreAssets(); } } } else { assets.stream().forEach(asset -> { if (!asset.getFolderItem().getType().equals(FolderItemType.FOLDER)) { final ClientResourceType assetResourceType = assetClassifier.findResourceType(asset.getFolderItem()); final String assetName = Utils.getBaseFileName(asset.getFolderItem().getFileName(), assetResourceType.getSuffix()); view.addAsset(assetName, getAssetPath(asset), assetResourceType.getDescription(), assetResourceType.getIcon(), getLastModifiedTime(asset), getCreatedTime(asset), detailsCommand((Path) asset.getFolderItem().getItem()), selectCommand((Path) asset.getFolderItem().getItem())); } }); } } public void filterUpdate(@Observes final FilterUpdateEvent event) { view.setFilterName(event.getName()); onUpdateAssets(); } private boolean isFilterEmpty() { return view.getFilterValue().isEmpty(); } private String getAssetPath(final AssetInfo asset) { final String fullPath = ((Path) asset.getFolderItem().getItem()).toURI(); final String projectRootPath = projectInfo.getProject().getRootPath().toURI(); final String relativeAssetPath = fullPath.substring(projectRootPath.length() + 1); final String decodedRelativeAssetPath = URIUtil.decode(relativeAssetPath); return decodedRelativeAssetPath; } @WorkbenchPartTitle public String getTitle() { return "Project Screen"; } @WorkbenchPartView public UberElement<ProjectScreen> getView() { return view; } public void onToFirstPage() { view.setPageNumber(1); loadProjectInfo(); } public void onToNextPage() { view.setPageNumber(view.getPageNumber() + 1); loadProjectInfo(); } public void onToPrevious() { view.setPageNumber(view.getPageNumber() - 1); loadProjectInfo(); } protected void reload() { Scheduler.get().scheduleFixedDelay(new Scheduler.RepeatingCommand() { @Override public boolean execute() { loadProjectInfo(); return false; } }, 1000); } public interface View extends UberElement<ProjectScreen> { void setProjectName(String projectName); void clearAssets(); void addAsset(final String assetName, final String assetPath, final String assetType, final IsWidget assetIcon, final String lastModifiedTime, final String createdTime, final Command details, final Command select); String getFilterValue(); void setFilterName(String name); Integer getPageNumber(); void setPageNumber(final int pageNumber); Integer getStep(); void range(final int from, final int to); void showIndexingIncomplete(); void hideEmptyState(); void showSearchHitNothing(); void showNoMoreAssets(); void setForwardDisabled(final boolean disabled); void setBackwardDisabled(final boolean disabled); } /** * This class is needed in situations where you open the project screen, but the indexing has not yet finished. * <p/> * It keeps reloading the file list from the backend server until either the page is full or * when the indexing runs out of files and stops. */ private class Reloader { private boolean active = false; private int previousAmount = -1; public void check(final List<AssetInfo> assetsList) { if (assets != null && assetsList.size() <= previousAmount && !assets.isEmpty()) { active = false; } if (assetsList.isEmpty() && getFirstIndex() == 0 && filterIsNotSet()) { active = true; } if (active && getFirstIndex() != 0) { active = false; } if (assetsList.size() == view.getStep()) { active = false; } previousAmount = assetsList.size(); if (active) { reload(); } } private boolean filterIsNotSet() { return view.getFilterValue() == null || view.getFilterValue().trim().isEmpty(); } } }