1 31 32 package org.antlr.works.debugger.input; 33 34 import org.antlr.xjlib.foundation.XJSystem; 35 import org.antlr.xjlib.foundation.notification.XJNotificationCenter; 36 import org.antlr.xjlib.foundation.notification.XJNotificationObserver; 37 import org.antlr.runtime.Token; 38 import org.antlr.works.debugger.Debugger; 39 import org.antlr.works.prefs.AWPrefs; 40 import org.antlr.works.prefs.AWPrefsDialog; 41 import org.antlr.works.utils.TextPane; 42 import org.antlr.works.utils.TextPaneDelegate; 43 44 import javax.swing.*; 45 import javax.swing.text.AttributeSet ; 46 import javax.swing.text.BadLocationException ; 47 import javax.swing.text.SimpleAttributeSet ; 48 import javax.swing.text.StyleConstants ; 49 import java.awt.*; 50 import java.awt.event.MouseAdapter ; 51 import java.awt.event.MouseEvent ; 52 import java.awt.event.MouseMotionAdapter ; 53 import java.awt.geom.GeneralPath ; 54 import java.util.*; 55 56 public class DBInputProcessorToken implements DBInputProcessor, TextPaneDelegate, XJNotificationObserver { 57 58 public static final Color HIGHLIGHTED_COLOR = new Color(0, 0.5f, 1, 0.4f); 59 public static final Color INPUT_BREAKPOINT_COLOR = new Color(1, 0.2f, 0, 0.5f); 60 61 protected Debugger debugger; 62 protected TextPane textPane; 63 protected int mouseIndex = -1; 64 65 protected LinkedList<Integer > inputTokenIndexes = new LinkedList<Integer >(); 66 protected Map<Integer ,DBInputTextTokenInfo> indexToTokenInfoMap = new HashMap<Integer , DBInputTextTokenInfo>(); 67 protected Map<Integer ,AttributeSet > indexToConsumeAttributeMap = new HashMap<Integer , AttributeSet >(); 68 protected Set <Integer > lookaheadTokenIndexes = new HashSet<Integer >(); 69 70 71 protected int currentTokenIndex; 72 73 74 protected int currentTokenIndexInText; 75 76 77 protected int locationLine; 78 protected int locationCharInLine; 79 80 81 protected Set <Integer > inputBreakpointIndexes = new HashSet<Integer >(); 82 83 protected SimpleAttributeSet attributeNonConsumed; 84 protected SimpleAttributeSet attributeConsume; 85 protected SimpleAttributeSet attributeConsumeHidden; 86 protected SimpleAttributeSet attributeConsumeDead; 87 protected SimpleAttributeSet attributeLookahead; 88 89 protected boolean drawTokensBox; 90 91 public DBInputProcessorToken(Debugger debugger, TextPane textPane) { 92 this.debugger = debugger; 93 94 this.textPane = textPane; 95 this.textPane.setDelegate(this); 96 this.textPane.addMouseListener(new MyMouseListener()); 97 this.textPane.addMouseMotionListener(new MyMouseMotionListener()); 98 99 drawTokensBox = false; 100 101 reset(); 102 createTextAttributes(); 103 104 XJNotificationCenter.defaultCenter().addObserver(this, AWPrefsDialog.NOTIF_PREFS_APPLIED); 105 } 106 107 public void close() { 108 XJNotificationCenter.defaultCenter().removeObserver(this); 109 } 110 111 public void setDrawTokensBox(boolean flag) { 112 drawTokensBox = flag; 113 textPane.repaint(); 114 } 115 116 public boolean isTokensBoxVisible() { 117 return drawTokensBox; 118 } 119 120 public int getCurrentTokenIndex() { 121 return currentTokenIndex; 122 } 123 124 public void setLocation(int line, int charInLine) { 125 this.locationLine = line; 126 this.locationCharInLine = charInLine; 127 } 128 129 public void consumeToken(Token token, int flavor) { 130 if(ignoreToken(token)) 131 return; 132 133 SimpleAttributeSet attr = null; 134 switch(flavor) { 135 case TOKEN_NORMAL: attr = attributeConsume; break; 136 case TOKEN_HIDDEN: attr = attributeConsumeHidden; break; 137 case TOKEN_DEAD: attr = attributeConsumeDead; break; 138 } 139 addToken(token); 140 addConsumeAttribute(token, attr); 141 removeTokenLT(token); 142 } 143 144 public void LT(Token token) { 145 addToken(token); 146 addTokenLT(token); 147 } 148 149 154 public boolean ignoreToken(Token t) { 155 if(!XJSystem.isWindows()) 156 return false; 157 158 Token ct = getCurrentToken(); 159 if(ct == null) 160 return false; 161 162 return ct.getText().equals("\r") && t.getText().equals("\n"); 163 } 164 165 public void addConsumeAttribute(Token token, AttributeSet attribute) { 166 indexToConsumeAttributeMap.put(token.getTokenIndex(), attribute); 167 } 168 169 public void addTokenLT(Token token) { 170 lookaheadTokenIndexes.add(token.getTokenIndex()); 171 } 172 173 public void removeTokenLT(Token token) { 174 lookaheadTokenIndexes.remove(Integer.valueOf(token.getTokenIndex())); 175 } 176 177 public void removeAllLT() { 178 lookaheadTokenIndexes.clear(); 179 } 180 181 public void stop() { 182 inputBreakpointIndexes.clear(); 183 } 184 185 public void reset() { 186 textPane.setText(""); 187 textPane.setCharacterAttributes(SimpleAttributeSet.EMPTY, true); 188 189 currentTokenIndex = -1; 190 currentTokenIndexInText = 0; 191 192 inputTokenIndexes.clear(); 193 indexToTokenInfoMap.clear(); 194 indexToConsumeAttributeMap.clear(); 195 lookaheadTokenIndexes.clear(); 196 } 197 198 public void rewindAll() { 199 rewind(-1); 200 } 201 202 public void rewind(int start) { 203 currentTokenIndex = start; 204 205 208 for (Integer idx : inputTokenIndexes) { 209 if (idx >= start) { 210 indexToConsumeAttributeMap.remove(idx); 211 lookaheadTokenIndexes.remove(idx); 212 } 213 } 214 } 215 216 public void addToken(Token token) { 217 int index = token.getTokenIndex(); 218 if(index == -1) { 219 return; 221 } 222 223 currentTokenIndex = index; 224 225 226 227 if(!indexToTokenInfoMap.containsKey(index)) { 228 if(inputTokenIndexes.isEmpty()) 229 inputTokenIndexes.add((Integer )index); 230 else { 231 for(int i=inputTokenIndexes.size()-1; i >= 0; i--) { 232 Integer n = inputTokenIndexes.get(i); 233 if(n < index) { 234 inputTokenIndexes.add(i+1, (Integer )index); 235 break; 236 } 237 } 238 } 239 } 240 241 244 245 indexToTokenInfoMap.put((Integer )index, new DBInputTextTokenInfo(token, locationLine, locationCharInLine)); 246 } 247 248 public Token getCurrentToken() { 249 DBInputTextTokenInfo info = indexToTokenInfoMap.get(getCurrentTokenIndex()); 250 if(info == null) 251 return null; 252 else 253 return info.token; 254 } 255 256 public String renderTokensText() { 257 currentTokenIndexInText = 0; 258 StringBuffer text = new StringBuffer (); 259 for (Integer idx : inputTokenIndexes) { 260 DBInputTextTokenInfo info = indexToTokenInfoMap.get(idx); 261 info.setStart(text.length()); 262 text.append(info.getText()); 263 264 if (idx == getCurrentTokenIndex()) 265 currentTokenIndexInText = info.start; 266 } 267 return text.toString(); 268 } 269 270 public void render() { 271 272 273 String text = renderTokensText(); 274 textPane.setText(text); 275 textPane.getStyledDocument().setCharacterAttributes(0, text.length(), SimpleAttributeSet.EMPTY, true); 276 277 278 for (Integer idx : inputTokenIndexes) { 279 DBInputTextTokenInfo info = indexToTokenInfoMap.get(idx); 280 AttributeSet attribute = indexToConsumeAttributeMap.get(idx); 281 if (attribute == null) 282 attribute = attributeNonConsumed; 283 284 285 if (lookaheadTokenIndexes.contains(idx)) 286 attribute = attributeLookahead; 287 288 textPane.getStyledDocument().setCharacterAttributes(info.start, info.end, attribute, true); 289 } 290 } 291 292 public void updateOnBreakEvent() { 293 render(); 294 295 298 SwingUtilities.invokeLater(new Runnable () { 299 public void run() { 300 try { 301 textPane.scrollRectToVisible(textPane.modelToView(currentTokenIndexInText)); 302 } catch (BadLocationException e) { 303 debugger.getConsole().print(e); 304 } 305 } 306 }); 307 } 308 309 public void createTextAttributes() { 310 attributeNonConsumed = new SimpleAttributeSet (); 311 StyleConstants.setForeground(attributeNonConsumed, AWPrefs.getNonConsumedTokenColor()); 312 313 attributeConsume = new SimpleAttributeSet (); 314 StyleConstants.setForeground(attributeConsume, AWPrefs.getConsumedTokenColor()); 315 316 attributeConsumeHidden = new SimpleAttributeSet (); 317 StyleConstants.setForeground(attributeConsumeHidden, AWPrefs.getHiddenTokenColor()); 318 319 attributeConsumeDead = new SimpleAttributeSet (); 320 StyleConstants.setForeground(attributeConsumeDead, AWPrefs.getDeadTokenColor()); 321 322 attributeLookahead = new SimpleAttributeSet (); 323 StyleConstants.setForeground(attributeLookahead, AWPrefs.getLookaheadTokenColor()); 324 StyleConstants.setItalic(attributeLookahead, true); 325 } 326 327 public void textPaneDidPaint(Graphics g) { 328 for (DBInputTextTokenInfo info : indexToTokenInfoMap.values()) { 329 if (drawTokensBox) 330 drawToken(info, (Graphics2D) g, Color.red, false); 331 332 if (inputBreakpointIndexes.contains(Integer.valueOf(info.token.getTokenIndex()))) 333 drawToken(info, (Graphics2D) g, INPUT_BREAKPOINT_COLOR, true); 334 else if (mouseIndex >= info.start && mouseIndex < info.end) 335 drawToken(info, (Graphics2D) g, HIGHLIGHTED_COLOR, true); 336 } 337 } 338 339 public void drawToken(DBInputTextTokenInfo info, Graphics2D g, Color c, boolean fill) { 340 g.setColor(c); 341 try { 342 Rectangle r1 = textPane.modelToView(info.start); 343 Rectangle r2 = textPane.modelToView(info.end); 344 345 if(r2.y > r1.y) { 346 350 GeneralPath gp = new GeneralPath (); 351 352 Rectangle r = null; 353 Rectangle pr = null; 354 int line_y = r1.y; 355 356 gp.moveTo(r1.x, r1.y); 357 for(int index=info.start; index<info.end; index++) { 358 r = textPane.modelToView(index); 359 if(r.y > line_y) { 360 line_y = r.y; 364 if(pr != null) { 365 gp.lineTo(pr.x+pr.width, pr.y); 366 gp.lineTo(pr.x+pr.width, pr.y+pr.height); 367 } 368 } 369 pr = r; 370 } 371 if(r != null) { 372 gp.lineTo(r.x+r.width, r.y); 373 gp.lineTo(r.x+r.width, r.y+r.height); 374 375 gp.lineTo(r1.x, r.y+r.height); 376 gp.lineTo(r1.x, r1.y); 377 } 378 if(fill) 379 g.fill(gp); 380 else 381 g.draw(gp); 382 } else { 383 if(fill) 384 g.fillRect(r1.x, r1.y, r2.x-r1.x, r1.height); 385 else 386 g.drawRect(r1.x, r1.y, r2.x-r1.x, r1.height); 387 } 388 } catch (BadLocationException e) { 389 } 391 } 392 393 public DBInputTextTokenInfo getTokenInfoAtTokenIndex(int index) { 394 return indexToTokenInfoMap.get(index); 395 } 396 397 public DBInputTextTokenInfo getTokenInfoAtPositionIndex(int index) { 398 for (DBInputTextTokenInfo info : indexToTokenInfoMap.values()) { 399 if (index >= info.start && index < info.end) 400 return info; 401 } 402 return null; 403 } 404 405 public boolean isBreakpointAtToken(Token token) { 406 return inputBreakpointIndexes.contains(Integer.valueOf(token.getTokenIndex())); 407 } 408 409 412 public void highlightToken(int index) { 413 mouseIndex = index; 414 textPane.repaint(); 415 } 416 417 420 public void selectToken(Token t) { 421 if(t == null) { 422 highlightToken(-1); 423 return; 424 } 425 426 DBInputTextTokenInfo info = getTokenInfoForToken(t); 427 if(info != null) 428 highlightToken(info.start); 429 else 430 highlightToken(-1); 431 } 432 433 public DBInputTextTokenInfo getTokenInfoForToken(Token t) { 434 for (DBInputTextTokenInfo info : indexToTokenInfoMap.values()) { 435 if (info.token.getTokenIndex() == t.getTokenIndex() && 437 info.token.getType() == t.getType()) 438 return info; 439 } 440 return null; 441 } 442 443 public void notificationFire(Object source, String name) { 444 if(name.equals(AWPrefsDialog.NOTIF_PREFS_APPLIED)) { 445 createTextAttributes(); 446 } 447 } 448 449 protected class MyMouseListener extends MouseAdapter { 450 451 public void mousePressed(MouseEvent e) { 452 highlightToken(textPane.getTextIndexAtLocation(e.getPoint())); 453 if(mouseIndex == -1) 454 return; 455 456 DBInputTextTokenInfo info = getTokenInfoAtPositionIndex(mouseIndex); 457 if(info == null) 458 return; 459 460 boolean shiftKey = (e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) == MouseEvent.SHIFT_DOWN_MASK; 461 if(e.getButton() == MouseEvent.BUTTON1 && !shiftKey) { 462 debugger.selectToken(info.token, info.line, info.charInLine); 463 } else { 464 Integer index = info.token.getTokenIndex(); 465 if(inputBreakpointIndexes.contains(index)) 466 inputBreakpointIndexes.remove(index); 467 else 468 inputBreakpointIndexes.add(index); 469 } 470 } 471 472 public void mouseExited(MouseEvent e) { 473 highlightToken(-1); 474 } 475 } 476 477 protected class MyMouseMotionListener extends MouseMotionAdapter { 478 479 public void mouseMoved(MouseEvent e) { 480 mouseIndex = textPane.getTextIndexAtLocation(e.getPoint()); 481 textPane.repaint(); 482 } 483 } 484 } 485 | Popular Tags |