fixed EDU-233, switched to flat model in offset listener

This commit is contained in:
liana.bakradze
2014-10-26 23:02:56 +03:00
parent 06d844e145
commit 7567c0fda3
8 changed files with 132 additions and 157 deletions
@@ -1,24 +1,23 @@
package org.jetbrains.plugins.coursecreator;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.impl.event.DocumentEventImpl;
import org.jetbrains.plugins.coursecreator.format.TaskFile;
import org.jetbrains.plugins.coursecreator.format.TaskWindow;
import java.util.ArrayList;
import java.util.List;
/**
* author: liana
* data: 7/16/14.
* Listens changes in study files and updates
* coordinates of all the windows in current task file
*/
public abstract class CCDocumentListener extends DocumentAdapter {
private final TaskFile myTaskFile;
private int myOldLine;
private int myOldLineStartOffset;
private TaskWindow myTaskWindow;
private List<TaskWindowWrapper> myTaskWindows = new ArrayList<TaskWindowWrapper>();
public CCDocumentListener(TaskFile taskFile) {
myTaskFile = taskFile;
@@ -29,39 +28,71 @@ public abstract class CCDocumentListener extends DocumentAdapter {
// with fragments containing "\n"
@Override
public void beforeDocumentChange(DocumentEvent e) {
int offset = e.getOffset();
int oldEnd = offset + e.getOldLength();
Document document = e.getDocument();
myOldLine = document.getLineNumber(oldEnd);
myOldLineStartOffset = document.getLineStartOffset(myOldLine);
int line = document.getLineNumber(offset);
int offsetInLine = offset - document.getLineStartOffset(line);
LogicalPosition pos = new LogicalPosition(line, offsetInLine);
myTaskWindow = myTaskFile.getTaskWindow(document, pos);
myTaskWindows.clear();
for (TaskWindow taskWindow : myTaskFile.getTaskWindows()) {
int twStart = taskWindow.getRealStartOffset(document);
int length = useLength() ? taskWindow.getLength() : taskWindow.getReplacementLength();
int twEnd = twStart + length;
myTaskWindows.add(new TaskWindowWrapper(taskWindow, twStart, twEnd));
}
}
@Override
public void documentChanged(DocumentEvent e) {
if (e instanceof DocumentEventImpl) {
DocumentEventImpl event = (DocumentEventImpl)e;
Document document = e.getDocument();
int offset = e.getOffset();
int change = event.getNewLength() - event.getOldLength();
if (myTaskWindow != null) {
updateTaskWindowLength(e.getNewFragment(), myTaskWindow, change);
DocumentEventImpl event = (DocumentEventImpl)e;
Document document = e.getDocument();
int offset = e.getOffset();
int change = event.getNewLength() - event.getOldLength();
for (TaskWindowWrapper taskWindowWrapper : myTaskWindows) {
int twStart = taskWindowWrapper.getTwStart();
if (twStart > offset) {
twStart += change;
}
int twEnd = taskWindowWrapper.getTwEnd();
if (twEnd >= offset) {
twEnd += change;
}
TaskWindow taskWindow = taskWindowWrapper.getTaskWindow();
int line = document.getLineNumber(twStart);
int start = twStart - document.getLineStartOffset(line);
int length = twEnd - twStart;
taskWindow.setLine(line);
taskWindow.setStart(start);
if (useLength()) {
taskWindow.setLength(length);
} else {
taskWindow.setReplacementLength(length);
}
int newEnd = offset + event.getNewLength();
int newLine = document.getLineNumber(newEnd);
int lineChange = newLine - myOldLine;
myTaskFile.incrementLines(myOldLine + 1, lineChange);
int newEndOffsetInLine = offset + e.getNewLength() - document.getLineStartOffset(newLine);
int oldEndOffsetInLine = offset + e.getOldLength() - myOldLineStartOffset;
myTaskFile.updateLine(lineChange, myOldLine, newEndOffsetInLine, oldEndOffsetInLine, useLength());
}
}
}
protected abstract void updateTaskWindowLength(CharSequence fragment, TaskWindow taskWindow, int change);
protected abstract boolean useLength();
private static class TaskWindowWrapper {
public TaskWindow myTaskWindow;
public int myTwStart;
public int myTwEnd;
public TaskWindowWrapper(TaskWindow taskWindow, int twStart, int twEnd) {
myTaskWindow = taskWindow;
myTwStart = twStart;
myTwEnd = twEnd;
}
public int getTwStart() {
return myTwStart;
}
public int getTwEnd() {
return myTwEnd;
}
public TaskWindow getTaskWindow() {
return myTaskWindow;
}
}
}
@@ -72,12 +72,6 @@ public class CCEditorFactoryListener implements EditorFactoryListener {
super(taskFile);
}
@Override
protected void updateTaskWindowLength(CharSequence fragment, TaskWindow taskWindow, int change) {
int newLength = taskWindow.getReplacementLength() + change;
taskWindow.setReplacementLength(newLength <= 0 ? 0 : newLength);
}
@Override
protected boolean useLength() {
return false;
@@ -85,6 +85,7 @@ public class CCAddTaskWindow extends DumbAwareAction {
}
int index = taskFile.getTaskWindows().size() + 1;
taskFile.addTaskWindow(taskWindow, index);
taskFile.sortTaskWindows();
taskWindow.drawHighlighter(editor, false);
taskWindow.createGuardedBlocks(editor);
}
@@ -134,6 +134,9 @@ public class CCCreateCourseArchive extends DumbAwareAction {
final TaskFile taskFile = taskFiles.getValue();
TaskFile taskFileSaved = new TaskFile();
taskFile.copy(taskFileSaved);
for (TaskWindow taskWindow : taskFile.getTaskWindows()) {
taskWindow.setLength(taskWindow.getReplacementLength());
}
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
@Override
public void run() {
@@ -168,7 +171,7 @@ public class CCCreateCourseArchive extends DumbAwareAction {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
document.replaceString(offset, offset + taskWindow.getReplacementLength(), taskText);
document.replaceString(offset, offset + taskWindow.getLength(), taskText);
FileDocumentManager.getInstance().saveDocument(document);
}
});
@@ -254,11 +257,6 @@ public class CCCreateCourseArchive extends DumbAwareAction {
super(taskFile);
}
@Override
protected void updateTaskWindowLength(CharSequence fragment, TaskWindow taskWindow, int change) {
//we don't need to update task window length
}
@Override
protected boolean useLength() {
return true;
@@ -6,9 +6,9 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.coursecreator.CCProjectService;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TaskFile {
@@ -57,52 +57,6 @@ public class TaskFile {
return null;
}
/**
* Updates task window lines
*
* @param startLine lines greater than this line and including this line will be updated
* @param change change to be added to line numbers
*/
public void incrementLines(int startLine, int change) {
for (TaskWindow taskTaskWindow : task_windows) {
if (taskTaskWindow.getLine() >= startLine) {
taskTaskWindow.setLine(taskTaskWindow.getLine() + change);
}
}
}
/**
* Updates windows in specific line
*
* @param lineChange change in line number
* @param line line to be updated
* @param newEndOffsetInLine distance from line start to end of inserted fragment
* @param oldEndOffsetInLine distance from line start to end of changed fragment
*/
public void updateLine(int lineChange, int line, int newEndOffsetInLine, int oldEndOffsetInLine, boolean useLength) {
for (TaskWindow w : task_windows) {
if ((w.getLine() == line) && (w.getStart() > oldEndOffsetInLine)) {
int distance = w.getStart() - oldEndOffsetInLine;
boolean coveredByPrevTW = false;
int prevIndex = w.getIndex() - 1;
if (CCProjectService.indexIsValid(prevIndex, task_windows)) {
TaskWindow prevTW = task_windows.get(prevIndex - 1);
if (prevTW.getLine() == line) {
int prevLength = useLength ? prevTW.getLength() : prevTW.getReplacementLength();
int endOffset = prevTW.getStart() + prevLength;
if (endOffset >= newEndOffsetInLine) {
coveredByPrevTW = true;
}
}
}
if (lineChange != 0 || newEndOffsetInLine <= w.getStart() || coveredByPrevTW) {
w.setStart(distance + newEndOffsetInLine);
w.setLine(line + lineChange);
}
}
}
}
public void copy(@NotNull final TaskFile target) {
target.setIndex(myIndex);
for (TaskWindow taskWindow : task_windows) {
@@ -110,6 +64,7 @@ public class TaskFile {
taskWindow.getLength(), "");
target.getTaskWindows().add(savedWindow);
savedWindow.setIndex(taskWindow.getIndex());
savedWindow.setReplacementLength(taskWindow.getReplacementLength());
}
}
@@ -121,6 +76,8 @@ public class TaskFile {
}
taskWindowUpdated.setLine(taskWindow.getLine());
taskWindowUpdated.setStart(taskWindow.getStart());
taskWindowUpdated.setReplacementLength(taskWindow.getReplacementLength());
taskWindowUpdated.setLength(taskWindow.getLength());
}
}
@@ -142,4 +99,11 @@ public class TaskFile {
taskWindow.createGuardedBlocks(editor);
}
}
public void sortTaskWindows() {
Collections.sort(task_windows);
for (int i = 0; i < task_windows.size(); i++) {
task_windows.get(i).setIndex(i + 1);
}
}
}
@@ -20,7 +20,7 @@ import org.jetbrains.plugins.coursecreator.CCProjectService;
import java.io.File;
import java.util.List;
public class TaskWindow implements Comparable{
public class TaskWindow implements Comparable<TaskWindow> {
@Expose public int line;
@Expose public int start;
@@ -120,8 +120,7 @@ public class TaskWindow implements Comparable{
}
@Override
public int compareTo(Object o) {
TaskWindow taskWindow = (TaskWindow)o;
public int compareTo(@NotNull TaskWindow taskWindow) {
int lineDiff = line - taskWindow.line;
if (lineDiff == 0) {
return start - taskWindow.start;
@@ -154,4 +153,8 @@ public class TaskWindow implements Comparable{
.addRangeHighlighter(start, end, HighlighterLayer.LAST + 1, null, HighlighterTargetArea.EXACT_RANGE);
blocks.add(rh);
}
public void setLength(int length) {
this.length = length;
}
}
@@ -2,22 +2,22 @@ package com.jetbrains.python.edu;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.impl.event.DocumentEventImpl;
import com.jetbrains.python.edu.course.TaskFile;
import com.jetbrains.python.edu.course.TaskWindow;
import java.util.ArrayList;
import java.util.List;
/**
* Listens changes in study files and updates
* coordinates of all the windows in current task file
*/
public class StudyDocumentListener extends DocumentAdapter {
private final TaskFile myTaskFile;
private int myOldLine;
private int myOldLineStartOffset;
private TaskWindow myTaskWindow;
private List<TaskWindowWrapper> myTaskWindows = new ArrayList<TaskWindowWrapper>();
public StudyDocumentListener(TaskFile taskFile) {
myTaskFile = taskFile;
@@ -28,15 +28,13 @@ public class StudyDocumentListener extends DocumentAdapter {
// with fragments containing "\n"
@Override
public void beforeDocumentChange(DocumentEvent e) {
int offset = e.getOffset();
int oldEnd = offset + e.getOldLength();
Document document = e.getDocument();
myOldLine = document.getLineNumber(oldEnd);
myOldLineStartOffset = document.getLineStartOffset(myOldLine);
int line = document.getLineNumber(offset);
int offsetInLine = offset - document.getLineStartOffset(line);
LogicalPosition pos = new LogicalPosition(line, offsetInLine);
myTaskWindow = myTaskFile.getTaskWindow(document, pos);
myTaskWindows.clear();
for (TaskWindow taskWindow : myTaskFile.getTaskWindows()) {
int twStart = taskWindow.getRealStartOffset(document);
int twEnd = twStart + taskWindow.getLength();
myTaskWindows.add(new TaskWindowWrapper(taskWindow, twStart, twEnd));
}
}
@Override
@@ -46,17 +44,47 @@ public class StudyDocumentListener extends DocumentAdapter {
Document document = e.getDocument();
int offset = e.getOffset();
int change = event.getNewLength() - event.getOldLength();
if (myTaskWindow != null) {
int newLength = myTaskWindow.getLength() + change;
myTaskWindow.setLength(newLength <= 0 ? 0 : newLength);
for (TaskWindowWrapper taskWindowWrapper : myTaskWindows) {
int twStart = taskWindowWrapper.getTwStart();
if (twStart > offset) {
twStart += change;
}
int twEnd = taskWindowWrapper.getTwEnd();
if (twEnd >= offset) {
twEnd += change;
}
TaskWindow taskWindow = taskWindowWrapper.getTaskWindow();
int line = document.getLineNumber(twStart);
int start = twStart - document.getLineStartOffset(line);
int length = twEnd - twStart;
taskWindow.setLine(line);
taskWindow.setStart(start);
taskWindow.setLength(length);
}
int newEnd = offset + event.getNewLength();
int newLine = document.getLineNumber(newEnd);
int lineChange = newLine - myOldLine;
myTaskFile.incrementLines(myOldLine + 1, lineChange);
int newEndOffsetInLine = offset + e.getNewLength() - document.getLineStartOffset(newLine);
int oldEndOffsetInLine = offset + e.getOldLength() - myOldLineStartOffset;
myTaskFile.updateLine(lineChange, myOldLine, newEndOffsetInLine, oldEndOffsetInLine);
}
}
private static class TaskWindowWrapper {
public TaskWindow myTaskWindow;
public int myTwStart;
public int myTwEnd;
public TaskWindowWrapper(TaskWindow taskWindow, int twStart, int twEnd) {
myTaskWindow = taskWindow;
myTwStart = twStart;
myTwEnd = twEnd;
}
public int getTwStart() {
return myTwStart;
}
public int getTwEnd() {
return myTwEnd;
}
public TaskWindow getTaskWindow() {
return myTaskWindow;
}
}
}
@@ -127,20 +127,6 @@ public class TaskFile implements Stateful {
return null;
}
/**
* Updates task window lines
*
* @param startLine lines greater than this line and including this line will be updated
* @param change change to be added to line numbers
*/
public void incrementLines(int startLine, int change) {
for (TaskWindow taskTaskWindow : taskWindows) {
if (taskTaskWindow.getLine() >= startLine) {
taskTaskWindow.setLine(taskTaskWindow.getLine() + change);
}
}
}
/**
* Initializes state of task file
*
@@ -165,36 +151,6 @@ public class TaskFile implements Stateful {
myIndex = index;
}
/**
* Updates windows in specific line
*
* @param lineChange change in line number
* @param line line to be updated
* @param newEndOffsetInLine distance from line start to end of inserted fragment
* @param oldEndOffsetInLine distance from line start to end of changed fragment
*/
public void updateLine(int lineChange, int line, int newEndOffsetInLine, int oldEndOffsetInLine) {
for (TaskWindow w : taskWindows) {
if ((w.getLine() == line) && (w.getStart() > oldEndOffsetInLine)) {
int distance = w.getStart() - oldEndOffsetInLine;
boolean coveredByPrevTW = false;
int prevIndex = w.getIndex() - 1;
if (StudyUtils.indexIsValid(prevIndex, taskWindows)) {
TaskWindow prevTW = taskWindows.get(prevIndex);
if (prevTW.getLine() == line) {
int endOffset = prevTW.getStart() + prevTW.getLength();
if (endOffset >= newEndOffsetInLine) {
coveredByPrevTW = true;
}
}
}
if (lineChange != 0 || newEndOffsetInLine <= w.getStart() || coveredByPrevTW) {
w.setStart(distance + newEndOffsetInLine);
w.setLine(line + lineChange);
}
}
}
}
public static void copy(@NotNull final TaskFile source, @NotNull final TaskFile target) {
List<TaskWindow> sourceTaskWindows = source.getTaskWindows();