1 11 package org.eclipse.jdt.internal.ui.text; 12 13 import java.util.HashMap ; 14 import java.util.Iterator ; 15 import java.util.Map ; 16 17 import org.eclipse.text.edits.MalformedTreeException; 18 import org.eclipse.text.edits.TextEdit; 19 20 import org.eclipse.core.runtime.Assert; 21 22 import org.eclipse.swt.SWT; 23 import org.eclipse.swt.custom.VerifyKeyListener; 24 import org.eclipse.swt.events.VerifyEvent; 25 import org.eclipse.swt.graphics.Point; 26 27 import org.eclipse.jface.text.BadLocationException; 28 import org.eclipse.jface.text.IDocument; 29 import org.eclipse.jface.text.IRegion; 30 import org.eclipse.jface.text.ITextViewer; 31 import org.eclipse.jface.text.ITextViewerExtension; 32 import org.eclipse.jface.text.TextViewer; 33 34 import org.eclipse.jdt.internal.ui.text.TypingRun.ChangeType; 35 36 37 38 50 public class SmartBackspaceManager { 51 52 53 59 public static final class UndoSpec { 60 private final int triggerOffset; 61 private final IRegion selection; 62 private final TextEdit[] undoEdits; 63 private final UndoSpec child; 64 int lives; 65 66 88 public UndoSpec(int triggerOffset, IRegion selection, TextEdit[] edits, int lives, UndoSpec child) { 89 Assert.isLegal(triggerOffset >= 0); 90 Assert.isLegal(selection != null); 91 Assert.isLegal(lives >= 0); 92 Assert.isLegal(edits != null); 93 Assert.isLegal(edits.length > 0); 94 for (int i= 0; i < edits.length; i++) { 95 Assert.isLegal(edits[i] != null); 96 } 97 98 this.triggerOffset= triggerOffset; 99 this.selection= selection; 100 this.undoEdits= edits; 101 this.lives= lives; 102 this.child= child; 103 } 104 } 105 106 107 private class BackspaceListener implements VerifyKeyListener { 108 109 112 public void verifyKey(VerifyEvent event) { 113 if (fViewer != null && isBackspace(event)) { 114 int offset= getCaretOffset(); 115 UndoSpec spec= removeEdit(offset); 116 if (spec != null) { 117 try { 118 beginChange(); 119 for (int i= 0; i < spec.undoEdits.length; i++) { 120 spec.undoEdits[i].apply(getDocument(), TextEdit.UPDATE_REGIONS); 121 } 122 fViewer.setSelectedRange(spec.selection.getOffset(), spec.selection.getLength()); 123 if (spec.child != null) 124 register(spec.child); 125 } catch (MalformedTreeException e) { 126 return; 128 } catch (BadLocationException e) { 129 return; 131 } finally { 132 endChange(); 133 } 134 event.doit= false; 135 } 136 137 } 138 } 139 140 private void beginChange() { 141 ITextViewer viewer= fViewer; 142 if (viewer instanceof TextViewer) { 143 TextViewer v= (TextViewer) viewer; 144 v.getRewriteTarget().beginCompoundChange(); 145 } 146 } 147 148 private void endChange() { 149 ITextViewer viewer= fViewer; 150 if (viewer instanceof TextViewer) { 151 TextViewer v= (TextViewer) viewer; 152 v.getRewriteTarget().endCompoundChange(); 153 } 154 } 155 156 private boolean isBackspace(VerifyEvent event) { 157 return event.doit == true && event.character == SWT.BS && event.stateMask == 0; 158 } 159 160 private int getCaretOffset() { 161 ITextViewer viewer= fViewer; 162 Point point= viewer.getSelectedRange(); 163 return point.x; 164 } 165 166 } 167 168 private ITextViewer fViewer; 169 private BackspaceListener fBackspaceListener; 170 private Map fSpecs; 171 private TypingRunDetector fRunDetector; 172 private ITypingRunListener fRunListener; 173 174 180 public void register(UndoSpec spec) { 181 if (fViewer == null) 182 throw new IllegalStateException (); 183 184 ensureListenerInstalled(); 185 addEdit(spec); 186 } 187 188 private void addEdit(UndoSpec spec) { 189 Integer i= new Integer (spec.triggerOffset); 190 fSpecs.put(i, spec); 191 } 192 193 private UndoSpec removeEdit(int offset) { 194 Integer i= new Integer (offset); 195 UndoSpec spec= (UndoSpec) fSpecs.remove(i); 196 return spec; 197 } 198 199 private void ensureListenerInstalled() { 200 if (fBackspaceListener == null) { 201 fBackspaceListener= new BackspaceListener(); 202 ITextViewer viewer= fViewer; 203 if (viewer instanceof ITextViewerExtension) 204 ((ITextViewerExtension) viewer).prependVerifyKeyListener(fBackspaceListener); 205 else 206 viewer.getTextWidget().addVerifyKeyListener(fBackspaceListener); 207 } 208 } 209 210 private void ensureListenerRemoved() { 211 if (fBackspaceListener != null) { 212 ITextViewer viewer= fViewer; 213 if (viewer instanceof ITextViewerExtension) 214 ((ITextViewerExtension) viewer).removeVerifyKeyListener(fBackspaceListener); 215 else 216 viewer.getTextWidget().removeVerifyKeyListener(fBackspaceListener); 217 fBackspaceListener= null; 218 } 219 } 220 221 private IDocument getDocument() { 222 return fViewer.getDocument(); 223 } 224 225 230 public void install(ITextViewer viewer) { 231 Assert.isLegal(viewer != null); 232 233 fViewer= viewer; 234 fSpecs= new HashMap (); 235 fRunDetector= new TypingRunDetector(); 236 fRunDetector.install(viewer); 237 fRunListener= new ITypingRunListener() { 238 239 242 public void typingRunStarted(TypingRun run) { 243 } 244 245 248 public void typingRunEnded(TypingRun run, ChangeType reason) { 249 if (reason == TypingRun.SELECTION) 250 fSpecs.clear(); 251 else 252 prune(); 253 } 254 }; 255 fRunDetector.addTypingRunListener(fRunListener); 256 } 257 258 private void prune() { 259 for (Iterator it= fSpecs.values().iterator(); it.hasNext();) { 260 UndoSpec spec= (UndoSpec) it.next(); 261 if (--spec.lives < 0) 262 it.remove(); 263 } 264 } 265 266 270 public void uninstall() { 271 if (fViewer != null) { 272 fRunDetector.removeTypingRunListener(fRunListener); 273 fRunDetector.uninstall(); 274 fRunDetector= null; 275 ensureListenerRemoved(); 276 fViewer= null; 277 } 278 } 279 } 280 | Popular Tags |