/* * Copyright 2000-2012 JetBrains s.r.o. * * 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.intellij.ide.util.gotoByName; import com.intellij.util.diff.Diff; import com.intellij.util.diff.FilesTooBigForDiffException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; public class ModelDiff { @Nullable public static List<Cmd> createDiffCmds(@NotNull Model<Object> listModel, @NotNull Object[] oldElements, @NotNull Object[] newElements) { Diff.Change change = null; try { change = Diff.buildChanges(oldElements, newElements); } catch (FilesTooBigForDiffException e) { // should not occur } if (change == null) { return null; } List<Cmd> commands = new ArrayList<Cmd>(); int inserted = 0; int deleted = 0; while (change != null) { if (change.deleted > 0) { final int start = change.line0 + inserted - deleted; commands.add(new RemoveCmd<Object>(listModel, start, start + change.deleted - 1)); } if (change.inserted > 0) { for (int i = 0; i < change.inserted; i++) { commands.add(new InsertCmd<Object>(listModel, change.line0 + i + inserted - deleted, newElements[change.line1 + i])); } } deleted += change.deleted; inserted += change.inserted; change = change.link; } return commands; } public interface Cmd { void apply(); int translateSelection(int row); } public interface Model<T> { void addToModel(int index, T element); void removeRangeFromModel(int start, int end); } private static class RemoveCmd<T> implements Cmd { private final Model<T> myListModel; private final int start; private final int end; private RemoveCmd(@NotNull Model<T> model, final int start, final int end) { myListModel = model; this.start = start; this.end = end; } @Override public void apply() { myListModel.removeRangeFromModel(start, end); } @Override public int translateSelection(int row) { if (row < start) return row; if (row >= end) return row - (end-start); return start-1; } @Override public String toString() { return "-["+start+", "+end+"]"; } } private static class InsertCmd<T> implements Cmd { private final Model<T> myListModel; private final int idx; private final T element; private InsertCmd(@NotNull Model<T> model, final int idx, @NotNull T element) { myListModel = model; this.idx = idx; this.element = element; } @Override public void apply() { //System.out.println("Adding: "+this+"-> "+element); myListModel.addToModel(idx, element); } @Override public int translateSelection(int row) { return idx > row ? row : row + 1; } @Override public String toString() { return "+["+idx+"]"; } } }