All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.teamapps.ux.component.workspacelayout.LayoutApplyer Maven / Gradle / Ivy

There is a newer version: 0.9.194
Show newest version
/*-
 * ========================LICENSE_START=================================
 * TeamApps
 * ---
 * Copyright (C) 2014 - 2024 TeamApps.org
 * ---
 * 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.
 * =========================LICENSE_END==================================
 */
package org.teamapps.ux.component.workspacelayout;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.teamapps.dto.UiWorkSpaceLayoutItem;
import org.teamapps.dto.UiWorkSpaceLayoutSplitItem;
import org.teamapps.dto.UiWorkSpaceLayoutViewGroupItem;
import org.teamapps.ux.component.splitpane.SplitSizePolicy;
import org.teamapps.ux.component.workspacelayout.definition.LayoutItemDefinition;
import org.teamapps.ux.component.workspacelayout.definition.SplitPaneDefinition;
import org.teamapps.ux.component.workspacelayout.definition.ViewGroupDefinition;

import java.util.*;
import java.util.stream.Collectors;

class LayoutApplyer {

	private static final Logger LOGGER = LoggerFactory.getLogger(LayoutApplyer.class);

	private final WorkSpaceLayout workSpaceLayout;

	private Map descriptorItemById;
	private Set descriptorViewNames;
	private Map itemsById;
	private Map viewsByName;

	public LayoutApplyer(WorkSpaceLayout workSpaceLayout) {
		this.workSpaceLayout = workSpaceLayout;
	}

	public Map applyFromUiLayoutDescriptor(
			Map currentRootItemsByWindowId,
			Map newRootDescriptorsByWindowId
	) {
		Map wrappedDescriptors = newRootDescriptorsByWindowId.entrySet().stream()
				.collect(Collectors.toMap(entry -> entry.getKey(), entry -> createWrapperFromUi(entry.getValue())));
		return apply(currentRootItemsByWindowId, wrappedDescriptors);
	}

	public Map applyFromLayoutDefinition(
			Map currentRootItemsByWindowId,
			Map newRootDescriptorsByWindowId
	) {
		Map wrappedDescriptors = newRootDescriptorsByWindowId.entrySet().stream()
				.collect(Collectors.toMap(entry -> entry.getKey(), entry -> createWrapperFromDefinition(entry.getValue())));
		return apply(currentRootItemsByWindowId, wrappedDescriptors);
	}

	public Map apply(
			Map currentRootItemsByWindowId,
			Map newRootDescriptorsByWindowId
	) {
		this.reset();

		newRootDescriptorsByWindowId.forEach((windowId, layoutDescriptor) -> this.putToDescriptorDictionaries(layoutDescriptor));
		currentRootItemsByWindowId.forEach((windowId, currentRootItem) -> this.putToServerItemDictionaries(currentRootItem));

		currentRootItemsByWindowId.forEach((windowId, currentRootItem) -> {
			LayoutItemWrapper newLayoutDescriptor = newRootDescriptorsByWindowId.get(windowId);
			this.cleanupUnknownServerItems(currentRootItem, newLayoutDescriptor, null);
		});


		Map newRootItemsByWindowId = newRootDescriptorsByWindowId.entrySet().stream()
				.collect(Collectors.toMap(e -> e.getKey(), e -> this.addNewStructure(e.getValue(), null, false)));
		return newRootItemsByWindowId;
	}

	private void reset() {
		descriptorItemById = new HashMap<>();
		descriptorViewNames = new HashSet<>();
		itemsById = new HashMap<>();
		viewsByName = new HashMap<>();
	}

	private void putToDescriptorDictionaries(LayoutItemWrapper descriptorItem) {
		this.descriptorItemById.put(descriptorItem.getId(), descriptorItem);
		if (descriptorItem instanceof ViewGroupWrapper) {
			ViewGroupWrapper viewGroupItem = (ViewGroupWrapper) descriptorItem;
			this.descriptorViewNames.addAll(viewGroupItem.getViewNames());
		} else if (descriptorItem instanceof SplitPaneWrapper) {
			SplitPaneWrapper splitItem = (SplitPaneWrapper) descriptorItem;
			if (splitItem.getFirstChild() != null) {
				this.putToDescriptorDictionaries(splitItem.getFirstChild());
			}
			if (splitItem.getLastChild() != null) {
				this.putToDescriptorDictionaries(splitItem.getLastChild());
			}
		}
	}

	private void putToServerItemDictionaries(WorkSpaceLayoutItem item) {
		if (item == null) {
			return;
		}
		this.itemsById.put(item.getId(), item);
		if (item instanceof WorkSpaceLayoutViewGroup) {
			((WorkSpaceLayoutViewGroup) item).getViews().forEach(view -> this.viewsByName.put(view.getId(), view));
		} else if (item instanceof WorkSpaceLayoutSplitPane) {
			WorkSpaceLayoutItem firstChild = ((WorkSpaceLayoutSplitPane) item).getFirstChild();
			if (firstChild != null) {
				this.putToServerItemDictionaries(firstChild);
			}
			WorkSpaceLayoutItem lastChild = ((WorkSpaceLayoutSplitPane) item).getLastChild();
			if (lastChild != null) {
				this.putToServerItemDictionaries(lastChild);
			}
		}
	}

	public void cleanupUnknownServerItems(WorkSpaceLayoutItem item, LayoutItemWrapper descriptorItem, WorkSpaceLayoutSplitPane parent) {
		// descriptorItem may be null for recursive executions of this method!
		if (descriptorItem != null && Objects.equals(descriptorItem.getId(), item.getId())) {
			if (item instanceof WorkSpaceLayoutSplitPane) {
				WorkSpaceLayoutSplitPane splitPane = (WorkSpaceLayoutSplitPane) item;
				WorkSpaceLayoutItem firstChild = splitPane.getFirstChild();
				if (firstChild != null) {
					this.cleanupUnknownServerItems(firstChild, ((SplitPaneWrapper) descriptorItem).getFirstChild(), splitPane);
				}
				WorkSpaceLayoutItem lastChild = splitPane.getLastChild();
				if (lastChild != null) {
					this.cleanupUnknownServerItems(lastChild, ((SplitPaneWrapper) descriptorItem).getLastChild(), splitPane);
				}
			} else if (item instanceof WorkSpaceLayoutViewGroup viewGroupItem) {
				ViewGroupWrapper viewGroupWrapper = (ViewGroupWrapper) descriptorItem;
				List viewNames = viewGroupWrapper.getViewNames();
				removeUnknownViews(viewGroupItem, viewNames);
				viewGroupItem.getAllViews().stream()
						.filter(view -> view.getId().equals(viewGroupWrapper.getSelectedViewName()))
						.findFirst()
						.ifPresent(viewGroupItem::setSelectedViewSilently);
			}
		} else {
			LayoutItemWrapper correspondingDescriptorItem = this.descriptorItemById.get(item.getId());
			if (correspondingDescriptorItem != null) {
				this.cleanupUnknownServerItems(item, correspondingDescriptorItem, null);
			} else {
				// not referenced in the descriptor! however, descendants might well be referenced in the descriptor!
				if (item instanceof WorkSpaceLayoutViewGroup) {
					this.removeUnknownViews((WorkSpaceLayoutViewGroup) item, Collections.emptyList());
				} else if (item instanceof WorkSpaceLayoutSplitPane) {
					this.cleanupUnknownServerItems(((WorkSpaceLayoutSplitPane) item).getFirstChild(), null, (WorkSpaceLayoutSplitPane) item);
					this.cleanupUnknownServerItems(((WorkSpaceLayoutSplitPane) item).getLastChild(), null, (WorkSpaceLayoutSplitPane) item);
				}
			}
			if (parent != null) {
				if (item == parent.getFirstChild()) {
					parent.setFirstChildSilently(null);
				} else {
					parent.setLastChildSilently(null);
				}
			} // otherwise this is the root item... nothing to do, since it will be exchanged, anyway.
		}
	}

	private void removeUnknownViews(WorkSpaceLayoutViewGroup viewGroup, List descriptorViewNames) {
		List viewsToBeRemoved = viewGroup.getViews().stream()
				.filter(view -> !descriptorViewNames.contains(view.getId()))
				.collect(Collectors.toList());
		viewsToBeRemoved.forEach(viewGroup::handleViewRemovedByClient);
	}

	private WorkSpaceLayoutItem addNewStructure(LayoutItemWrapper descriptor, WorkSpaceLayoutSplitPane parent, boolean firstChild) {
		if (descriptor == null) {
			return null;
		}
		WorkSpaceLayoutItem serverSideItem = this.itemsById.get(descriptor.getId());
		WorkSpaceLayoutItem item;
		if (serverSideItem != null) {
			item = serverSideItem;
			if (descriptor instanceof SplitPaneWrapper) {
				SplitPaneWrapper splitDescriptor = (SplitPaneWrapper) descriptor;
				WorkSpaceLayoutSplitPane splitPaneItem = (WorkSpaceLayoutSplitPane) serverSideItem;
				this.addNewStructure(splitDescriptor.getFirstChild(), splitPaneItem, true);
				this.addNewStructure(splitDescriptor.getLastChild(), splitPaneItem, false);

				splitPaneItem.setSizePolicySilently(SplitSizePolicy.valueOf(splitDescriptor.getSizePolicy().name()));
				splitPaneItem.setReferenceChildSizeSilently(splitDescriptor.getReferenceChildSize());
			} else if (descriptor instanceof ViewGroupWrapper) {
				ViewGroupWrapper viewGroupDescriptor = (ViewGroupWrapper) descriptor;
				WorkSpaceLayoutViewGroup viewGroup = (WorkSpaceLayoutViewGroup) serverSideItem;
				addViews(viewGroup, viewGroupDescriptor);
				viewGroup.setPanelStateSilently(ViewGroupPanelState.valueOf(viewGroupDescriptor.getPanelState().name()));
			}
		} else { // this is a descriptor for a new item
			item = this.createTreeItemFromLayoutDescriptor(descriptor);
		}

		if (parent != null) {
			if (firstChild) {
				parent.setFirstChildSilently(item);
			} else {
				parent.setLastChildSilently(item);
			}
		}
		return item;
	}

	private WorkSpaceLayoutItem createTreeItemFromLayoutDescriptor(LayoutItemWrapper descriptor) {
		if (descriptor instanceof ViewGroupWrapper) {
			ViewGroupWrapper viewGroupWrapper = (ViewGroupWrapper) descriptor;
			var tabPanelItem = new WorkSpaceLayoutViewGroup(descriptor.getId(), viewGroupWrapper.isPersistent(), workSpaceLayout);
			this.addViews(tabPanelItem, viewGroupWrapper);
			return tabPanelItem;
		} else {
			SplitPaneWrapper splitDescriptor = (SplitPaneWrapper) descriptor;
			var splitPaneItem = new WorkSpaceLayoutSplitPane(
					descriptor.getId(),
					SplitDirection.valueOf(splitDescriptor.getSplitDirection().name()),
					SplitSizePolicy.valueOf(splitDescriptor.getSizePolicy().name()),
					splitDescriptor.getReferenceChildSize(),
					workSpaceLayout
			);
			splitPaneItem.setFirstChildSilently(this.addNewStructure(splitDescriptor.getFirstChild(), splitPaneItem, true));
			splitPaneItem.setLastChildSilently(this.addNewStructure(splitDescriptor.getLastChild(), splitPaneItem, false));
			return splitPaneItem;
		}
	}

	private void addViews(WorkSpaceLayoutViewGroup viewGroup, ViewGroupWrapper viewGroupDescriptor) {
		for (int i = 0; i < viewGroupDescriptor.getViewNames().size(); i++) {
			String viewName = viewGroupDescriptor.getViewNames().get(i);
			boolean selected = Objects.equals(viewName, viewGroupDescriptor.getSelectedViewName()) || viewGroupDescriptor.getSelectedViewName() == null && i == 0;
			WorkSpaceLayoutView view = viewsByName.get(viewName);
			if (view != null) {
				viewGroup.addViewSilently(view, i, selected);
			}
		}
	}

	private static LayoutItemWrapper createWrapperFromUi(UiWorkSpaceLayoutItem child) {
		if (child instanceof UiWorkSpaceLayoutSplitItem) {
			return new UiWorkSpaceLayoutSplitItemWrapper(((UiWorkSpaceLayoutSplitItem) child));
		} else if (child instanceof UiWorkSpaceLayoutViewGroupItem) {
			return new UiWorkSpaceLayoutViewGroupItemWrapper(((UiWorkSpaceLayoutViewGroupItem) child));
		} else {
			throw new IllegalArgumentException("Unknown layout item type " + child.getClass().getCanonicalName());
		}
	}

	private static LayoutApplyer.LayoutItemWrapper createWrapperFromDefinition(LayoutItemDefinition child) {
		if (child instanceof SplitPaneDefinition) {
			return new LayoutSplitPaneDefinitionWrapper((SplitPaneDefinition) child);
		} else if (child instanceof ViewGroupDefinition) {
			return new LayoutViewGroupDefinitionWrapper(((ViewGroupDefinition) child));
		} else {
			throw new IllegalArgumentException("Unknown layout item type " + child.getClass().getCanonicalName());
		}
	}

	private interface LayoutItemWrapper {
		String getId();
	}

	private interface SplitPaneWrapper extends LayoutItemWrapper {
		SplitDirection getSplitDirection();

		SplitSizePolicy getSizePolicy();

		float getReferenceChildSize();

		LayoutItemWrapper getFirstChild();

		LayoutItemWrapper getLastChild();
	}

	private interface ViewGroupWrapper extends LayoutItemWrapper {
		List getViewNames();

		String getSelectedViewName();

		boolean isPersistent();

		ViewGroupPanelState getPanelState();
	}

	private static class UiWorkSpaceLayoutSplitItemWrapper implements SplitPaneWrapper {
		private final UiWorkSpaceLayoutSplitItem item;

		public UiWorkSpaceLayoutSplitItemWrapper(UiWorkSpaceLayoutSplitItem item) {
			this.item = item;
		}

		@Override
		public String getId() {
			return item.getId();
		}

		@Override
		public SplitDirection getSplitDirection() {
			return SplitDirection.valueOf(item.getSplitDirection().name());
		}

		@Override
		public SplitSizePolicy getSizePolicy() {
			return SplitSizePolicy.valueOf(item.getSizePolicy().name());
		}

		@Override
		public float getReferenceChildSize() {
			return item.getReferenceChildSize();
		}

		@Override
		public LayoutItemWrapper getFirstChild() {
			return createWrapperFromUi(item.getFirstChild());
		}

		@Override
		public LayoutItemWrapper getLastChild() {
			return createWrapperFromUi(item.getLastChild());
		}

	}

	private static class UiWorkSpaceLayoutViewGroupItemWrapper implements ViewGroupWrapper {
		private final UiWorkSpaceLayoutViewGroupItem item;

		public UiWorkSpaceLayoutViewGroupItemWrapper(UiWorkSpaceLayoutViewGroupItem item) {
			this.item = item;
		}

		@Override
		public List getViewNames() {
			return item.getViewNames();
		}

		@Override
		public String getSelectedViewName() {
			return item.getSelectedViewName();
		}

		@Override
		public boolean isPersistent() {
			return item.getPersistent();
		}

		@Override
		public ViewGroupPanelState getPanelState() {
			return ViewGroupPanelState.valueOf(item.getPanelState().name());
		}

		@Override
		public String getId() {
			return item.getId();
		}
	}

	private static class LayoutSplitPaneDefinitionWrapper implements SplitPaneWrapper {
		private final SplitPaneDefinition item;

		public LayoutSplitPaneDefinitionWrapper(SplitPaneDefinition item) {
			this.item = item;
		}

		@Override
		public String getId() {
			return item.getId();
		}

		@Override
		public SplitDirection getSplitDirection() {
			return item.getSplitDirection();
		}

		@Override
		public SplitSizePolicy getSizePolicy() {
			return item.getSizePolicy();
		}

		@Override
		public float getReferenceChildSize() {
			return item.getReferenceChildSize();
		}

		@Override
		public LayoutItemWrapper getFirstChild() {
			return createWrapperFromDefinition(item.getFirstChild());
		}

		@Override
		public LayoutItemWrapper getLastChild() {
			return createWrapperFromDefinition(item.getLastChild());
		}

	}

	private static class LayoutViewGroupDefinitionWrapper implements ViewGroupWrapper {
		private final ViewGroupDefinition item;

		public LayoutViewGroupDefinitionWrapper(ViewGroupDefinition item) {
			this.item = item;
		}

		@Override
		public String getId() {
			return item.getId();
		}

		@Override
		public List getViewNames() {
			return item.getViews().stream()
					.map(v -> v.getId())
					.collect(Collectors.toList());
		}

		@Override
		public String getSelectedViewName() {
			return item.getSelectedView() != null ? item.getSelectedView().getId() : null;
		}

		@Override
		public boolean isPersistent() {
			return item.isPersistent();
		}

		@Override
		public ViewGroupPanelState getPanelState() {
			return ViewGroupPanelState.valueOf(item.getPanelState().name());
		}

	}


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy