PageRenderTime 67ms CodeModel.GetById 52ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/bundles/plugins-trunk/RubyPlugin/src/org/jedit/ruby/structure/BufferChangeHandler.java

#
Java | 227 lines | 163 code | 42 blank | 22 comment | 28 complexity | 6474e524d0db7c78970c2f4a545bb81b MD5 | raw file
  1/*
  2 * BufferChangeHandler.java - 
  3 *
  4 * Copyright 2005 Robert McKinnon
  5 *
  6 * This program is free software; you can redistribute it and/or
  7 * modify it under the terms of the GNU General Public License
  8 * as published by the Free Software Foundation; either version 2
  9 * of the License, or any later version.
 10 *
 11 * This program is distributed in the hope that it will be useful,
 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14 * GNU General Public License for more details.
 15 *
 16 * You should have received a copy of the GNU General Public License
 17 * along with this program; if not, write to the Free Software
 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 19 */
 20
 21package org.jedit.ruby.structure;
 22
 23import org.gjt.sp.jedit.buffer.BufferAdapter;
 24import org.gjt.sp.jedit.Buffer;
 25import org.gjt.sp.jedit.View;
 26import org.gjt.sp.jedit.jEdit;
 27import org.gjt.sp.jedit.textarea.JEditTextArea;
 28import org.jedit.ruby.RubyPlugin;
 29import org.jedit.ruby.utils.EditorView;
 30
 31import java.util.*;
 32import java.util.List;
 33import java.awt.*;
 34
 35/**
 36 * @author robmckinnon at users.sourceforge.net
 37 */
 38public class BufferChangeHandler extends BufferAdapter {
 39
 40    private static final BufferChangeHandler instance = new BufferChangeHandler();
 41
 42    private final Map<String, Map<Integer, Edit>> fileToEdit = new HashMap<String, Map<Integer, Edit>>();
 43    private final List<Edit> allEdits = new ArrayList<Edit>();
 44
 45    private boolean previousEditAction;
 46    private int editLocationIndex = 0;
 47
 48    private BufferChangeHandler() {
 49    }
 50
 51    public static BufferChangeHandler instance() {
 52        return instance;
 53    }
 54
 55    public void preContentRemoved(Buffer buffer, int startLine, int offset, int numLines, int length) {
 56    }
 57
 58    public void transactionComplete(Buffer buffer) {
 59        EditorView view = RubyPlugin.getActiveView();
 60        int line = view.getLineAtCaret();
 61        Map<Integer, Edit> lineEdits = getLineEdits(buffer.getPath());
 62
 63        if (lineEdits.containsKey(line)) {
 64            lineEdits.get(line).offsetInLine = view.getCaretOffsetInLine();
 65        }
 66    }
 67
 68    public void contentInserted(Buffer buffer, int startLine, int offset, int numLines, int length) {
 69        if (numLines > 0) {
 70            Map<Integer, Edit> lineEdits = getLineEdits(buffer.getPath());
 71            Collection<Edit> edits = new ArrayList<Edit>(lineEdits.values());
 72
 73            for (Edit edit : edits) {
 74                if (edit.line >= startLine) {
 75                    lineEdits.remove(edit.line);
 76                    edit.incrementLine(numLines);
 77                    lineEdits.put(edit.line, edit);
 78                }
 79            }
 80
 81        }
 82        if (numLines == 0) {
 83            updateEdits(buffer, startLine, offset + length - buffer.getLineStartOffset(startLine));
 84        } else {
 85            updateEdits(buffer, startLine, offset - buffer.getLineStartOffset(startLine));
 86        }
 87    }
 88
 89    public void contentRemoved(Buffer buffer, int startLine, int offset, int numLines, int length) {
 90        if (numLines > 0) {
 91            Map<Integer, Edit> lineEdits = getLineEdits(buffer.getPath());
 92
 93            for (int line = startLine; line < startLine + numLines; line++) {
 94                Edit edit = lineEdits.remove(line);
 95                allEdits.remove(edit);
 96            }
 97
 98            Collection<Edit> edits = new ArrayList<Edit>(lineEdits.values());
 99            for (Edit edit : edits) {
100                if (edit.line >= startLine + numLines) {
101                    lineEdits.remove(edit.line);
102                    edit.decrement(numLines);
103                    lineEdits.put(edit.line, edit);
104                }
105            }
106        }
107        updateEdits(buffer, startLine, offset - buffer.getLineStartOffset(startLine));
108    }
109
110    private void updateEdits(Buffer buffer, int line, int offsetInLine) {
111        String file = buffer.getPath();
112        Edit edit = new Edit(file, line, offsetInLine);
113        allEdits.remove(edit);
114        allEdits.add(edit);
115
116        Map<Integer, Edit> lineEdits = getLineEdits(file);
117        lineEdits.put(line, edit);
118
119        if (line > 0 && lineEdits.containsKey(line - 1)) {
120            removeEditAt(line - 1, lineEdits);
121        }
122
123        if (line < (buffer.getLineCount() - 1) && lineEdits.containsKey(line + 1)) {
124            removeEditAt(line + 1, lineEdits);
125        }
126    }
127
128    private void removeEditAt(int line, Map<Integer, Edit> lineEdits) {
129        Edit previousEdit = lineEdits.remove(line);
130        allEdits.remove(previousEdit);
131    }
132
133    public void gotoPreviousEdit(View view) {
134        setGotoPreviousEdit(true);
135
136        if (!allEdits.isEmpty() && editLocationIndex < allEdits.size()) {
137            editLocationIndex++;
138            final Edit edit = allEdits.get(allEdits.size() - editLocationIndex);
139
140            if (edit.file.equals(view.getBuffer().getPath())) {
141                gotoEdit(view.getTextArea(), edit);
142
143            } else {
144                Buffer buffer = jEdit.openFile(view, edit.file);
145                if (buffer != null) {
146                    view.goToBuffer(buffer);
147
148                    EventQueue.invokeLater(new Runnable() {
149                        public void run() {
150                            gotoEdit(jEdit.getActiveView().getTextArea(), edit);
151                        }
152                    });
153                } else {
154                    setGotoPreviousEdit(false);
155                }
156            }
157        } else {
158            setGotoPreviousEdit(false);
159        }
160    }
161
162    private void gotoEdit(JEditTextArea textArea, Edit edit) {
163        textArea.setCaretPosition(edit.getEditOffset(textArea));
164        setGotoPreviousEdit(false);
165    }
166
167    public boolean isGotoPreviousEditAction() {
168        return previousEditAction;
169    }
170
171    public void resetEditLocationIndex() {
172        editLocationIndex = 0;
173    }
174
175    public void setGotoPreviousEdit(boolean action) {
176        previousEditAction = action;
177    }
178
179    private Map<Integer, Edit> getLineEdits(String file) {
180        if (!fileToEdit.containsKey(file)) {
181            Map<Integer, Edit> lineToEdit = new HashMap<Integer, Edit>();
182            fileToEdit.put(file, lineToEdit);
183        }
184
185        return fileToEdit.get(file);
186    }
187
188    public static class Edit {
189        String file;
190        int line;
191        int offsetInLine;
192
193        public Edit(String file, int line, int offsetInLine) {
194            this.file = file;
195            this.line = line;
196            this.offsetInLine = offsetInLine;
197        }
198
199        private int getEditOffset(JEditTextArea textArea) {
200            if (line < textArea.getLineCount()) {
201                String lineText = textArea.getLineText(line);
202                int offsetInLineText = offsetInLine <= lineText.length() ? offsetInLine : lineText.length();
203                return textArea.getLineStartOffset(line) + offsetInLineText;
204            } else {
205                return textArea.getText().length();
206            }
207        }
208
209        public boolean equals(Object obj) {
210            Edit edit = (Edit)obj;
211            return file.equals(edit.file) && line == edit.line;
212        }
213
214        public int hashCode() {
215            return file.hashCode() + line;
216        }
217
218        public void incrementLine(int numLines) {
219            line += numLines;
220        }
221
222        public void decrement(int numLines) {
223            line -= numLines;
224        }
225    }
226
227}