blob: f4ae9bad5f467c563b965c1a312ad3615645f664 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package com.google.eclipse.elt.emulator.internal.model;
import java.util.*;
import org.eclipse.core.runtime.Assert;
import com.google.eclipse.elt.emulator.model.*;
class TerminalTextDataSnapshot implements ITerminalTextDataSnapshot {
// The changes of the current snapshot relative to the previous snapshot.
private volatile ISnapshotChanges currentChanges;
// Keeps track of changes that happened since the current snapshot has been made.
private ISnapshotChanges futureChanges;
// Is used as lock and is the reference to the terminal we take snapshots from.
private final TerminalTextData terminal;
// A snapshot copy of terminal. It does not need internal synchronization.
private final TerminalTextDataWindow snapshot;
private final List<SnapshotOutOfDateListener> listeners = new ArrayList<SnapshotOutOfDateListener>();
private boolean listenersNeedNotify;
private int interestWindowSize;
private int interestWindowStartLine;
TerminalTextDataSnapshot(TerminalTextData terminal) {
snapshot = new TerminalTextDataWindow();
this.terminal = terminal;
currentChanges = new SnapshotChanges(this.terminal.getHeight());
currentChanges.setTerminalChanged();
futureChanges = new SnapshotChanges(this.terminal.getHeight());
futureChanges.markLinesChanged(0, this.terminal.getHeight());
listenersNeedNotify = true;
interestWindowSize = -1;
}
@Override public void detach() {
terminal.removeSnapshot(this);
}
@Override public boolean isOutOfDate() {
// This is called from terminal, therefore we lock on terminal
synchronized (terminal) {
return futureChanges.hasChanged();
}
}
@Override public void updateSnapshot(boolean detectScrolling) {
// Make sure terminal does not change while we make the snapshot.
synchronized (terminal) {
// let's make the future changes current
currentChanges = futureChanges;
futureChanges = new SnapshotChanges(terminal.getHeight());
futureChanges.setInterestWindow(interestWindowStartLine, interestWindowSize);
// and update the snapshot
if (snapshot.getHeight() != terminal.getHeight() || snapshot.getWidth() != terminal.getWidth()) {
if (interestWindowSize == -1) {
snapshot.setWindow(0, terminal.getHeight());
}
// if the dimensions have changed, we need a full copy.
snapshot.copy(terminal);
// and we mark all lines as changed.
currentChanges.setAllChanged(terminal.getHeight());
} else {
// first we do the scroll on the copy
int start = currentChanges.getScrollWindowStartLine();
int lines = Math.min(currentChanges.getScrollWindowSize(), snapshot.getHeight() - start);
snapshot.scroll(start, lines, currentChanges.getScrollWindowShift());
// and then create the snapshot of the changed lines.
currentChanges.copyChangedLines(snapshot, terminal);
}
listenersNeedNotify = true;
snapshot.setCursorLine(terminal.getCursorLine());
snapshot.setCursorColumn(terminal.getCursorColumn());
}
if (!detectScrolling) {
// let's pretend there was no scrolling and convert the scrolling into line changes
currentChanges.convertScrollingIntoChanges();
}
}
@Override public char getChar(int line, int column) {
return snapshot.getChar(line, column);
}
@Override public int getHeight() {
return snapshot.getHeight();
}
@Override public LineSegment[] getLineSegments(int line, int column, int len) {
return snapshot.getLineSegments(line, column, len);
}
@Override public Style getStyle(int line, int column) {
return snapshot.getStyle(line, column);
}
@Override public int getWidth() {
return snapshot.getWidth();
}
@Override public int getFirstChangedLine() {
return currentChanges.getFirstChangedLine();
}
@Override public int getLastChangedLine() {
return currentChanges.getLastChangedLine();
}
@Override public boolean hasLineChanged(int line) {
return currentChanges.hasLineChanged(line);
}
@Override public boolean hasDimensionsChanged() {
return currentChanges.hasDimensionsChanged();
}
@Override public boolean hasTerminalChanged() {
return currentChanges.hasTerminalChanged();
}
@Override public int getScrollWindowStartLine() {
return currentChanges.getScrollWindowStartLine();
}
@Override public int getScrollWindowSize() {
return currentChanges.getScrollWindowSize();
}
@Override public int getScrollWindowShift() {
return currentChanges.getScrollWindowShift();
}
void markLineChanged(int line) {
futureChanges.markLineChanged(line);
futureChanges.setTerminalChanged();
notifyListers();
}
void markLinesChanged(int line, int size) {
futureChanges.markLinesChanged(line, size);
futureChanges.setTerminalChanged();
notifyListers();
}
void markDimensionsChanged() {
futureChanges.markDimensionsChanged();
futureChanges.setTerminalChanged();
notifyListers();
}
void markCursorChanged() {
futureChanges.markCursorChanged();
futureChanges.setTerminalChanged();
notifyListers();
}
void scroll(int startLine, int size, int shift) {
futureChanges.scroll(startLine, size, shift);
futureChanges.setTerminalChanged();
notifyListers();
}
private void notifyListers() {
synchronized (terminal) {
if (listenersNeedNotify) {
for (SnapshotOutOfDateListener listener : listeners) {
listener.snapshotOutOfDate(this);
}
listenersNeedNotify = false;
}
}
}
@Override public ITerminalTextDataSnapshot makeSnapshot() {
return snapshot.makeSnapshot();
}
@Override synchronized public void addListener(SnapshotOutOfDateListener listener) {
listeners.add(listener);
}
@Override synchronized public void removeListener(SnapshotOutOfDateListener listener) {
listeners.remove(listener);
}
@Override public String toString() {
return snapshot.toString();
}
@Override public int getInterestWindowSize() {
return interestWindowSize;
}
@Override public int getInterestWindowStartLine() {
return interestWindowStartLine;
}
@Override public void setInterestWindow(int startLine, int size) {
Assert.isTrue(startLine >= 0 && size >= 0);
interestWindowStartLine = startLine;
interestWindowSize = size;
snapshot.setWindow(startLine, size);
futureChanges.setInterestWindow(startLine, size);
notifyListers();
}
@Override public char[] getChars(int line) {
return snapshot.getChars(line);
}
@Override public Style[] getStyles(int line) {
return snapshot.getStyles(line);
}
@Override public int getCursorColumn() {
return snapshot.getCursorColumn();
}
@Override public int getCursorLine() {
return snapshot.getCursorLine();
}
@Override public ITerminalTextData getTerminalTextData() {
return terminal;
}
}