/* Copyright (c) 2010, Carl Burch. License information is located in the
* com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */
package com.cburch.draw.actions;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.cburch.draw.model.CanvasModel;
import com.cburch.draw.model.CanvasObject;
import com.cburch.draw.model.ReorderRequest;
import com.cburch.draw.util.ZOrder;
public class ModelReorderAction extends ModelAction {
public static ModelReorderAction createRaise(CanvasModel model,
Collection<? extends CanvasObject> objects) {
List<ReorderRequest> reqs = new ArrayList<ReorderRequest>();
Map<CanvasObject, Integer> zmap = ZOrder.getZIndex(objects, model);
for(Map.Entry<CanvasObject, Integer> entry : zmap.entrySet()) {
CanvasObject obj = entry.getKey();
int from = entry.getValue().intValue();
CanvasObject above = ZOrder.getObjectAbove(obj, model, objects);
if (above != null) {
int to = ZOrder.getZIndex(above, model);
if (objects.contains(above)) {
to--;
}
reqs.add(new ReorderRequest(obj, from, to));
}
}
if (reqs.isEmpty()) {
return null;
} else {
Collections.sort(reqs, ReorderRequest.DESCENDING_FROM);
repairRequests(reqs);
return new ModelReorderAction(model, reqs);
}
}
public static ModelReorderAction createLower(CanvasModel model,
Collection<? extends CanvasObject> objects) {
List<ReorderRequest> reqs = new ArrayList<ReorderRequest>();
Map<CanvasObject, Integer> zmap = ZOrder.getZIndex(objects, model);
for(Map.Entry<CanvasObject, Integer> entry : zmap.entrySet()) {
CanvasObject obj = entry.getKey();
int from = entry.getValue().intValue();
CanvasObject above = ZOrder.getObjectBelow(obj, model, objects);
if (above != null) {
int to = ZOrder.getZIndex(above, model);
if (objects.contains(above)) {
to++;
}
reqs.add(new ReorderRequest(obj, from, to));
}
}
if (reqs.isEmpty()) {
return null;
} else {
Collections.sort(reqs, ReorderRequest.ASCENDING_FROM);
repairRequests(reqs);
return new ModelReorderAction(model, reqs);
}
}
public static ModelReorderAction createRaiseTop(CanvasModel model,
Collection<? extends CanvasObject> objects) {
List<ReorderRequest> reqs = new ArrayList<ReorderRequest>();
Map<CanvasObject, Integer> zmap = ZOrder.getZIndex(objects, model);
int to = model.getObjectsFromBottom().size() - 1;
for(Map.Entry<CanvasObject, Integer> entry : zmap.entrySet()) {
CanvasObject obj = entry.getKey();
int from = entry.getValue().intValue();
reqs.add(new ReorderRequest(obj, from, to));
}
if (reqs.isEmpty()) {
return null;
} else {
Collections.sort(reqs, ReorderRequest.ASCENDING_FROM);
repairRequests(reqs);
return new ModelReorderAction(model, reqs);
}
}
public static ModelReorderAction createLowerBottom(CanvasModel model,
Collection<? extends CanvasObject> objects) {
List<ReorderRequest> reqs = new ArrayList<ReorderRequest>();
Map<CanvasObject, Integer> zmap = ZOrder.getZIndex(objects, model);
int to = 0;
for(Map.Entry<CanvasObject, Integer> entry : zmap.entrySet()) {
CanvasObject obj = entry.getKey();
int from = entry.getValue().intValue();
reqs.add(new ReorderRequest(obj, from, to));
}
if (reqs.isEmpty()) {
return null;
} else {
Collections.sort(reqs, ReorderRequest.ASCENDING_FROM);
repairRequests(reqs);
return new ModelReorderAction(model, reqs);
}
}
private static void repairRequests(List<ReorderRequest> reqs) {
for (int i = 0, n = reqs.size(); i < n; i++) {
ReorderRequest req = reqs.get(i);
int from = req.getFromIndex();
int to = req.getToIndex();
for (int j = 0; j < i; j++) {
ReorderRequest prev = reqs.get(j);
int prevFrom = prev.getFromIndex();
int prevTo = prev.getToIndex();
if (prevFrom <= from && from < prevTo) {
from--;
} else if (prevTo <= from && from < prevFrom) {
from++;
}
if (prevFrom <= to && to < prevTo) {
to--;
} else if (prevTo <= to && to < prevFrom) {
to++;
}
}
if (from != req.getFromIndex() || to != req.getToIndex()) {
reqs.set(i, new ReorderRequest(req.getObject(), from, to));
}
}
for (int i = reqs.size() - 1; i >= 0; i--) {
ReorderRequest req = reqs.get(i);
if (req.getFromIndex() == req.getToIndex()) {
reqs.remove(i);
}
}
}
private ArrayList<ReorderRequest> requests;
private ArrayList<CanvasObject> objects;
private int type;
public ModelReorderAction(CanvasModel model, List<ReorderRequest> requests) {
super(model);
this.requests = new ArrayList<ReorderRequest>(requests);
this.objects = new ArrayList<CanvasObject>(requests.size());
for (ReorderRequest r : requests) {
objects.add(r.getObject());
}
int type = 0; // 0 = mixed/unknown, -1 = to greater index, 1 = to smaller index
for (ReorderRequest r : requests) {
int thisType;
int from = r.getFromIndex();
int to = r.getToIndex();
if (to < from) {
thisType = -1;
} else if (to > from) {
thisType = 1;
} else {
thisType = 0;
}
if (type == 2) {
type = thisType;
} else if (type != thisType) {
type = 0;
break;
}
}
this.type = type;
}
public List<ReorderRequest> getReorderRequests() {
return Collections.unmodifiableList(requests);
}
@Override
public Collection<CanvasObject> getObjects() {
return objects;
}
@Override
public String getName() {
if (type < 0) {
return Strings.get("actionRaise", getShapesName(objects));
} else if (type > 0) {
return Strings.get("actionLower", getShapesName(objects));
} else {
return Strings.get("actionReorder", getShapesName(objects));
}
}
@Override
void doSub(CanvasModel model) {
model.reorderObjects(requests);
}
@Override
void undoSub(CanvasModel model) {
ArrayList<ReorderRequest> inv = new ArrayList<ReorderRequest>(requests.size());
for (int i = requests.size() - 1; i >= 0; i--) {
ReorderRequest r = requests.get(i);
inv.add(new ReorderRequest(r.getObject(), r.getToIndex(),
r.getFromIndex()));
}
model.reorderObjects(inv);
}
}