From 7567c0fda36e57490ceaa4890e52fc61078d1804 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Sun, 26 Oct 2014 23:02:56 +0300 Subject: [PATCH] fixed EDU-233, switched to flat model in offset listener --- .../coursecreator/CCDocumentListener.java | 89 +++++++++++++------ .../CCEditorFactoryListener.java | 6 -- .../actions/CCAddTaskWindow.java | 1 + .../actions/CCCreateCourseArchive.java | 10 +-- .../coursecreator/format/TaskFile.java | 58 +++--------- .../coursecreator/format/TaskWindow.java | 9 +- .../python/edu/StudyDocumentListener.java | 72 ++++++++++----- .../jetbrains/python/edu/course/TaskFile.java | 44 --------- 8 files changed, 132 insertions(+), 157 deletions(-) diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCDocumentListener.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCDocumentListener.java index 3573216e9efa..b1917292df32 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCDocumentListener.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCDocumentListener.java @@ -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 myTaskWindows = new ArrayList(); + 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; + } + } } diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java index 74afc795b60a..24688c4b2709 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java @@ -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; diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCAddTaskWindow.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCAddTaskWindow.java index 951a5e85582b..e423da553d1b 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCAddTaskWindow.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCAddTaskWindow.java @@ -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); } diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCCreateCourseArchive.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCCreateCourseArchive.java index c201e4ddaee4..b5a0292db684 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCCreateCourseArchive.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCCreateCourseArchive.java @@ -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; diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java index c48a4f41d7e1..9fb10eaa179a 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java @@ -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); + } + } } diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java index dc7551929e30..385aaeddf26e 100644 --- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java +++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java @@ -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 { @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; + } } \ No newline at end of file diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java index 8955032aa408..848becfae1b1 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDocumentListener.java @@ -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 myTaskWindows = new ArrayList(); 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; } } } diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java b/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java index aaaef375a093..e9281e957855 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/course/TaskFile.java @@ -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 sourceTaskWindows = source.getTaskWindows();