| /* |
| * Copyright 2008 Google Inc. |
| * |
| * 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 com.google.gwt.resources.css.ast; |
| |
| import java.util.List; |
| |
| /** |
| * A visitor that can make structural modifications to a CSS tree. |
| */ |
| @SuppressWarnings("unchecked") |
| public class CssModVisitor extends CssVisitor { |
| private class ListContext<T extends CssNode> implements Context { |
| private int index; |
| private List list; |
| private boolean removed; |
| private boolean replaced; |
| |
| public boolean canInsert() { |
| return true; |
| } |
| |
| public boolean canRemove() { |
| return true; |
| } |
| |
| public void insertAfter(CssNode node) { |
| checkRemoved(); |
| list.add(index + 1, node); |
| didChange = true; |
| } |
| |
| public void insertBefore(CssNode node) { |
| checkRemoved(); |
| list.add(index++, node); |
| didChange = true; |
| } |
| |
| public void removeMe() { |
| checkState(); |
| list.remove(index--); |
| didChange = removed = true; |
| } |
| |
| public void replaceMe(CssNode node) { |
| checkState(); |
| checkReplacement((CssNode) list.get(index), node); |
| list.set(index, node); |
| didChange = replaced = true; |
| } |
| |
| protected void traverse(List<? extends CssNode> list) { |
| this.list = list; |
| for (index = 0; index < list.size(); ++index) { |
| removed = replaced = false; |
| doTraverse(list.get(index), this); |
| } |
| } |
| |
| private void checkRemoved() { |
| if (removed) { |
| throw new CssCompilerException("Node was already removed"); |
| } |
| } |
| |
| private void checkState() { |
| checkRemoved(); |
| if (replaced) { |
| throw new CssCompilerException("Node was already replaced"); |
| } |
| } |
| } |
| |
| protected static void checkReplacement(CssNode origNode, CssNode newNode) { |
| if (newNode == null) { |
| throw new CssCompilerException("Cannot replace with null"); |
| } |
| if (newNode == origNode) { |
| throw new CssCompilerException( |
| "The replacement is the same as the original"); |
| } |
| } |
| |
| private boolean didChange; |
| |
| public boolean didChange() { |
| return didChange; |
| } |
| |
| @Override |
| protected void doAcceptWithInsertRemove(List<? extends CssNode> list) { |
| ListContext context = new ListContext(); |
| context.traverse(list); |
| } |
| } |