/* * 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.uberfire.ext.layout.editor.client.components.container; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.enterprise.context.Dependent; import javax.enterprise.event.Event; import javax.enterprise.event.Observes; import javax.enterprise.inject.Instance; import javax.inject.Inject; import org.uberfire.client.mvp.UberElement; import org.uberfire.ext.layout.editor.api.editor.LayoutComponent; import org.uberfire.ext.layout.editor.api.editor.LayoutRow; import org.uberfire.ext.layout.editor.api.editor.LayoutTemplate; import org.uberfire.ext.layout.editor.client.api.ComponentDropEvent; import org.uberfire.ext.layout.editor.client.components.columns.Column; import org.uberfire.ext.layout.editor.client.components.rows.EmptyDropRow; import org.uberfire.ext.layout.editor.client.components.rows.Row; import org.uberfire.ext.layout.editor.client.components.rows.RowDnDEvent; import org.uberfire.ext.layout.editor.client.components.rows.RowDrop; import org.uberfire.ext.layout.editor.client.infra.BeanHelper; import org.uberfire.ext.layout.editor.client.infra.ColumnDrop; import org.uberfire.ext.layout.editor.client.infra.LayoutTemplateAdapter; import org.uberfire.ext.layout.editor.client.infra.UniqueIDGenerator; import org.uberfire.mvp.ParameterizedCommand; @Dependent public class Container { private final Instance<Row> rowInstance; private final Instance<EmptyDropRow> emptyDropRowInstance; private final View view; private LayoutTemplate layoutTemplate; private String id; private UniqueIDGenerator idGenerator = new UniqueIDGenerator(); private List<Row> rows = new ArrayList<>(); private EmptyDropRow emptyDropRow; private String layoutName; private String emptyTitleText; private String emptySubTitleText; private Map<String, String> properties = new HashMap<>(); private Event<ComponentDropEvent> componentDropEvent; @Inject public Container(final View view, Instance<Row> rowInstance, Instance<EmptyDropRow> emptyDropRowInstance, Event<ComponentDropEvent> componentDropEvent) { this.rowInstance = rowInstance; this.emptyDropRowInstance = emptyDropRowInstance; this.view = view; this.componentDropEvent = componentDropEvent; this.id = idGenerator.createContainerID(); } @PostConstruct public void setup() { view.init(this); init(); } @PreDestroy public void preDestroy() { for (Row row : rows) { destroy(row); } destroy(emptyDropRow); } private void init() { view.clear(); for (Row row : rows) { destroy(row); } rows = new ArrayList<>(); } private void createEmptyDropRow() { emptyDropRow = createEmptyRow(); view.addEmptyRow(emptyDropRow.getView()); } public void loadEmptyLayout(String layoutName, String emptyTitleText, String emptySubTitleText) { this.layoutName = layoutName; this.emptyTitleText = emptyTitleText; this.emptySubTitleText = emptySubTitleText; createEmptyDropRow(); } public void load(LayoutTemplate layoutTemplate, String emptyTitleText, String emptySubTitleText) { this.layoutTemplate = layoutTemplate; this.emptyTitleText = emptyTitleText; this.emptySubTitleText = emptySubTitleText; if (!layoutTemplate.isEmpty()) { this.layoutName = layoutTemplate.getName(); this.properties = layoutTemplate.getLayoutProperties(); for (LayoutRow layoutRow : layoutTemplate.getRows()) { rows.add(load(layoutRow)); } updateView(); } else { createEmptyDropRow(); } } public void reset() { init(); layoutTemplate = null; emptyTitleText = null; emptySubTitleText = null; layoutName = null; properties = null; emptyDropRow = null; } private EmptyDropRow createEmptyRow() { emptyDropRow = createInstanceEmptyDropRow(); emptyDropRow.init(createEmptyDropCommand(), emptyTitleText, emptySubTitleText); return emptyDropRow; } protected EmptyDropRow createInstanceEmptyDropRow() { EmptyDropRow emptyDropRow = emptyDropRowInstance.get(); emptyDropRow.setId(idGenerator.createRowID(id)); return emptyDropRow; } public ParameterizedCommand<RowDrop> createEmptyDropCommand() { return (drop) -> { destroy(emptyDropRow); notifyDrop(drop.getComponent()); rows.add(createRow(drop)); updateView(); }; } private void notifyDrop(LayoutComponent component) { componentDropEvent.fire(new ComponentDropEvent(component)); } private Row createRow(RowDrop drop) { final Row row = createInstanceRow(); row.init(createRowDropCommand(), createRemoveRowCommand(), createRemoveComponentCommand()); row.withOneColumn(drop.getComponent(), drop.newComponent()); view.addRow(row.getView()); return row; } private ParameterizedCommand<Row> createRemoveRowCommand() { return (row) -> { this.rows.remove(row); destroy(row); if (layoutIsEmpty()) { init(); createEmptyDropRow(); } else { updateView(); } }; } private ParameterizedCommand<ColumnDrop> createRemoveComponentCommand() { return drop -> removeOldComponent(drop.getOldColumn()); } private boolean layoutIsEmpty() { return rows.isEmpty(); } public ParameterizedCommand<RowDrop> createRowDropCommand() { return (dropRow) -> { List<Row> updatedRows = new ArrayList<>(); for (Row row : rows) { handleDrop(dropRow, updatedRows, row); } rows = updatedRows; getView(); }; } private void handleDrop(RowDrop dropRow, List<Row> updatedRows, Row row) { if (dropIsInthisRow(row, dropRow)) { if (dropRow.newComponent()) { addNewRow(row, dropRow, updatedRows); } else { handleMoveComponent(dropRow, updatedRows, row); } } else { updatedRows.add(row); } } private void handleMoveComponent(RowDrop dropRow, List<Row> updatedRows, Row row) { removeOldComponent(dropRow.getOldColumn()); addNewRow(row, dropRow, updatedRows); } private void removeOldComponent(Column column) { for (Row row : rows) { row.removeChildColumn(column); } } private void addNewRow(Row row, RowDrop dropRow, List<Row> newRows) { if (newRowIsBeforeThisRow(dropRow)) { newRows.add(createRow(dropRow)); if (!row.rowIsEmpty()) { newRows.add(row); } } else { if (!row.rowIsEmpty()) { newRows.add(row); } newRows.add(createRow(dropRow)); } notifyDrop(dropRow.getComponent()); } private boolean newRowIsBeforeThisRow(RowDrop dropRow) { return dropRow.getOrientation() == RowDrop.Orientation.BEFORE; } private boolean dropIsInthisRow(Row row, RowDrop dropRow) { return dropRow.getRowId() == row.getId(); } private void clearView() { view.clear(); } protected void swapRows(@Observes RowDnDEvent rowDndEvent) { List<Row> newRows = new ArrayList<>(); Row beginRow = lookForBeginningRow(rowDndEvent); if (beginRow != null) { for (Row row : rows) { if (row.getId() == rowDndEvent.getRowIdEnd()) { if (rowDndEvent.getOrientation() == RowDrop.Orientation.AFTER) { newRows.add(row); newRows.add(beginRow); } else { newRows.add(beginRow); newRows.add(row); } } else { if (row.getId() != beginRow.getId()) { newRows.add(row); } } } this.rows = newRows; } updateView(); } private Row lookForBeginningRow(@Observes RowDnDEvent rowDndEvent) { Row beginRow = null; for (Row row : rows) { if (row.getId() == rowDndEvent.getRowIdBegin()) { beginRow = row; } } return beginRow; } public String getLayoutName() { return layoutName; } private Row load(LayoutRow layoutRow) { final Row row = createInstanceRow(); row.load(createRowDropCommand(), layoutRow, createRemoveRowCommand(), createRemoveComponentCommand()); return row; } protected Row createInstanceRow() { Row row = rowInstance.get(); row.setId(idGenerator.createRowID(id)); return row; } public void addProperty(String key, String value) { properties.put(key, value); } public String getProperty(String key) { return properties.get(key); } public Map<String, String> getProperties() { return properties; } public LayoutTemplate toLayoutTemplate() { LayoutTemplate convert = LayoutTemplateAdapter.convert(this); return convert; } public List<Row> getRows() { return rows; } void updateView() { if (!rows.isEmpty()) { clearView(); for (Row row : rows) { view.addRow(row.getView()); } } } public UberElement<Container> getView() { updateView(); return view; } EmptyDropRow getEmptyDropRow() { return emptyDropRow; } protected void destroy(Object o) { BeanHelper.destroy(o); } public interface View extends UberElement<Container> { void addRow(UberElement<Row> view); void clear(); void addEmptyRow(UberElement<EmptyDropRow> emptyDropRow); } }