blob: b6aeeb486d2393066a0df3a528dca7c7c933fc00 [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
*
* 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 com.android.ide.common.layout;
import static com.android.SdkConstants.FQCN_TABLE_ROW;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.ide.common.api.DropFeedback;
import com.android.ide.common.api.IClientRulesEngine;
import com.android.ide.common.api.IMenuCallback;
import com.android.ide.common.api.INode;
import com.android.ide.common.api.INodeHandler;
import com.android.ide.common.api.IViewRule;
import com.android.ide.common.api.InsertType;
import com.android.ide.common.api.RuleAction;
import com.android.ide.common.api.SegmentType;
import java.net.URL;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* An {@link IViewRule} for android.widget.TableLayout.
*/
public class TableLayoutRule extends LinearLayoutRule {
// A table is a linear layout, but with a few differences:
// the default is vertical, not horizontal
// The fill of all children should be wrap_content
private static final String ACTION_ADD_ROW = "_addrow"; //$NON-NLS-1$
private static final String ACTION_REMOVE_ROW = "_removerow"; //$NON-NLS-1$
private static final URL ICON_ADD_ROW =
TableLayoutRule.class.getResource("addrow.png"); //$NON-NLS-1$
private static final URL ICON_REMOVE_ROW =
TableLayoutRule.class.getResource("removerow.png"); //$NON-NLS-1$
@Override
protected boolean isVertical(INode node) {
// Tables are always vertical
return true;
}
@Override
protected boolean supportsOrientation() {
return false;
}
@Override
public void onChildInserted(@NonNull INode child, @NonNull INode parent,
@NonNull InsertType insertType) {
// Overridden to inhibit the setting of layout_width/layout_height since
// it should always be match_parent
}
/**
* Add an explicit "Add Row" action to the context menu
*/
@Override
public void addContextMenuActions(@NonNull List<RuleAction> actions,
final @NonNull INode selectedNode) {
super.addContextMenuActions(actions, selectedNode);
IMenuCallback addTab = new IMenuCallback() {
@Override
public void action(
@NonNull RuleAction action,
@NonNull List<? extends INode> selectedNodes,
final @Nullable String valueId,
@Nullable Boolean newValue) {
final INode node = selectedNode;
INode newRow = node.appendChild(FQCN_TABLE_ROW);
mRulesEngine.select(Collections.singletonList(newRow));
}
};
actions.add(RuleAction.createAction("_addrow", "Add Row", addTab, null, 5, false)); //$NON-NLS-1$
}
@Override
public void addLayoutActions(
@NonNull List<RuleAction> actions,
final @NonNull INode parentNode,
final @NonNull List<? extends INode> children) {
super.addLayoutActions(actions, parentNode, children);
addTableLayoutActions(mRulesEngine, actions, parentNode, children);
}
/**
* Adds layout actions to add and remove toolbar items
*/
static void addTableLayoutActions(final IClientRulesEngine rulesEngine,
List<RuleAction> actions, final INode parentNode,
final List<? extends INode> children) {
IMenuCallback actionCallback = new IMenuCallback() {
@Override
public void action(
final @NonNull RuleAction action,
@NonNull List<? extends INode> selectedNodes,
final @Nullable String valueId,
final @Nullable Boolean newValue) {
parentNode.editXml("Add/Remove Table Row", new INodeHandler() {
@Override
public void handle(@NonNull INode n) {
if (action.getId().equals(ACTION_ADD_ROW)) {
// Determine the index of the selection, if any; if there is
// a selection, insert the row before the current row, otherwise
// append it to the table.
int index = -1;
INode[] rows = parentNode.getChildren();
if (children != null) {
findTableIndex:
for (INode child : children) {
// Find direct child of table layout
while (child != null && child.getParent() != parentNode) {
child = child.getParent();
}
if (child != null) {
// Compute index of direct child of table layout
for (int i = 0; i < rows.length; i++) {
if (rows[i] == child) {
index = i;
break findTableIndex;
}
}
}
}
}
INode newRow;
if (index == -1) {
newRow = parentNode.appendChild(FQCN_TABLE_ROW);
} else {
newRow = parentNode.insertChildAt(FQCN_TABLE_ROW, index);
}
rulesEngine.select(Collections.singletonList(newRow));
} else if (action.getId().equals(ACTION_REMOVE_ROW)) {
// Find the direct children of the TableLayout to delete;
// this is necessary since TableRow might also use
// this implementation, so the parentNode is the true
// TableLayout but the children might be grand children.
Set<INode> targets = new HashSet<INode>();
for (INode child : children) {
while (child != null && child.getParent() != parentNode) {
child = child.getParent();
}
if (child != null) {
targets.add(child);
}
}
for (INode target : targets) {
parentNode.removeChild(target);
}
}
}
});
}
};
// Add Row
actions.add(RuleAction.createSeparator(150));
actions.add(RuleAction.createAction(ACTION_ADD_ROW, "Add Table Row", actionCallback,
ICON_ADD_ROW, 160, false));
// Remove Row (if something is selected)
if (children != null && children.size() > 0) {
actions.add(RuleAction.createAction(ACTION_REMOVE_ROW, "Remove Table Row",
actionCallback, ICON_REMOVE_ROW, 170, false));
}
}
@Override
public void onCreate(@NonNull INode node, @NonNull INode parent,
@NonNull InsertType insertType) {
super.onCreate(node, parent, insertType);
if (insertType.isCreate()) {
// Start the table with 4 rows
for (int i = 0; i < 4; i++) {
node.appendChild(FQCN_TABLE_ROW);
}
}
}
@Override
public DropFeedback onResizeBegin(@NonNull INode child, @NonNull INode parent,
@Nullable SegmentType horizontalEdge, @Nullable SegmentType verticalEdge,
@Nullable Object childView, @Nullable Object parentView) {
// Children of a table layout cannot set their widths (it is controlled by column
// settings on the table). They can set their heights (though for TableRow, the
// height is always wrap_content).
if (horizontalEdge == null) { // Widths are edited by vertical edges.
// The user is not editing a vertical height so don't allow resizing at all
return null;
}
if (child.getFqcn().equals(FQCN_TABLE_ROW)) {
// TableRows are always WRAP_CONTENT
return null;
}
// Allow resizing heights only
return super.onResizeBegin(child, parent, horizontalEdge, null /*verticalEdge*/,
childView, parentView);
}
}