1 19 20 package org.netbeans.lib.editor.util.swing; 21 22 import java.util.Map ; 23 import javax.swing.event.DocumentEvent ; 24 import javax.swing.event.DocumentListener ; 25 import javax.swing.text.BadLocationException ; 26 import javax.swing.text.Document ; 27 import javax.swing.text.Element ; 28 import javax.swing.text.Segment ; 29 import javax.swing.text.StyledDocument ; 30 import javax.swing.undo.CannotRedoException ; 31 import javax.swing.undo.CannotUndoException ; 32 import javax.swing.undo.UndoableEdit ; 33 import org.netbeans.lib.editor.util.AbstractCharSequence; 34 import org.netbeans.lib.editor.util.CompactMap; 35 36 42 43 public final class DocumentUtilities { 44 45 private static final Object TYPING_MODIFICATION_DOCUMENT_PROPERTY = new Object (); 46 47 private static final Object TYPING_MODIFICATION_KEY = new Object (); 48 49 50 private DocumentUtilities() { 51 } 53 54 67 public static void addDocumentListener(Document doc, DocumentListener listener, 68 DocumentListenerPriority priority) { 69 if (!addPriorityDocumentListener(doc, listener, priority)) 70 doc.addDocumentListener(listener); 71 } 72 73 89 public static boolean addPriorityDocumentListener(Document doc, DocumentListener listener, 90 DocumentListenerPriority priority) { 91 PriorityDocumentListenerList priorityDocumentListenerList 92 = (PriorityDocumentListenerList)doc.getProperty(PriorityDocumentListenerList.class); 93 if (priorityDocumentListenerList != null) { 94 priorityDocumentListenerList.add(listener, priority.getPriority()); 95 return true; 96 } else 97 return false; 98 } 99 100 111 public static void removeDocumentListener(Document doc, DocumentListener listener, 112 DocumentListenerPriority priority) { 113 if (!removePriorityDocumentListener(doc, listener, priority)) 114 doc.removeDocumentListener(listener); 115 } 116 117 133 public static boolean removePriorityDocumentListener(Document doc, DocumentListener listener, 134 DocumentListenerPriority priority) { 135 PriorityDocumentListenerList priorityDocumentListenerList 136 = (PriorityDocumentListenerList)doc.getProperty(PriorityDocumentListenerList.class); 137 if (priorityDocumentListenerList != null) { 138 priorityDocumentListenerList.remove(listener, priority.getPriority()); 139 return true; 140 } else 141 return false; 142 } 143 144 176 public static DocumentListener initPriorityListening(Document doc) { 177 if (doc.getProperty(PriorityDocumentListenerList.class) != null) { 178 throw new IllegalStateException ( 179 "PriorityDocumentListenerList already initialized for doc=" + doc); } 181 PriorityDocumentListenerList listener = new PriorityDocumentListenerList(); 182 doc.putProperty(PriorityDocumentListenerList.class, listener); 183 return listener; 184 } 185 186 206 public static void setTypingModification(Document doc, boolean typingModification) { 207 doc.putProperty(TYPING_MODIFICATION_DOCUMENT_PROPERTY, Boolean.valueOf(typingModification)); 208 } 209 210 221 public static boolean isTypingModification(Document doc) { 222 Boolean b = (Boolean )doc.getProperty(TYPING_MODIFICATION_DOCUMENT_PROPERTY); 223 return (b != null) ? b.booleanValue() : false; 224 } 225 226 230 public static boolean isTypingModification(DocumentEvent evt) { 231 return isTypingModification(evt.getDocument()); 232 } 233 234 244 public static CharSequence getText(Document doc) { 245 CharSequence text = (CharSequence )doc.getProperty(CharSequence .class); 246 if (text == null) { 247 text = new DocumentCharSequence(doc); 248 doc.putProperty(CharSequence .class, text); 249 } 250 return text; 251 } 252 253 268 public static CharSequence getText(Document doc, int offset, int length) throws BadLocationException { 269 CharSequence text = (CharSequence )doc.getProperty(CharSequence .class); 270 if (text == null) { 271 text = new DocumentCharSequence(doc); 272 doc.putProperty(CharSequence .class, text); 273 } 274 try { 275 return text.subSequence(offset, offset + length); 276 } catch (IndexOutOfBoundsException e) { 277 int badOffset = offset; 278 if (offset >= 0 && offset + length > text.length()) { 279 badOffset = length; 280 } 281 throw new BadLocationException (e.getMessage(), badOffset); 282 } 283 } 284 285 292 public static void addEventPropertyStorage(DocumentEvent evt) { 293 if (!(evt instanceof UndoableEdit )) { 295 throw new IllegalStateException ("evt not instanceof UndoableEdit: " + evt); } 297 ((UndoableEdit )evt).addEdit(new EventPropertiesElementChange()); 298 } 299 300 307 public static Object getEventProperty(DocumentEvent evt, Object key) { 308 EventPropertiesElementChange change = (EventPropertiesElementChange) 309 evt.getChange(EventPropertiesElement.INSTANCE); 310 return (change != null) ? change.getProperty(key) : null; 311 } 312 313 320 public static void putEventProperty(DocumentEvent evt, Object key, Object value) { 321 EventPropertiesElementChange change = (EventPropertiesElementChange) 322 evt.getChange(EventPropertiesElement.INSTANCE); 323 if (change == null) { 324 throw new IllegalStateException ("addEventPropertyStorage() not called for evt=" + evt); } 326 change.putProperty(key, value); 327 } 328 329 341 public static void putEventProperty(DocumentEvent evt, Map.Entry mapEntry) { 342 if (mapEntry instanceof CompactMap.MapEntry) { 343 EventPropertiesElementChange change = (EventPropertiesElementChange) 344 evt.getChange(EventPropertiesElement.INSTANCE); 345 if (change == null) { 346 throw new IllegalStateException ("addEventPropertyStorage() not called for evt=" + evt); } 348 change.putEntry((CompactMap.MapEntry)mapEntry); 349 350 } else { 351 putEventProperty(evt, mapEntry.getKey(), mapEntry.getValue()); 352 } 353 } 354 355 362 public static int fixOffset(int offset, DocumentEvent evt) { 363 int modOffset = evt.getOffset(); 364 if (evt.getType() == DocumentEvent.EventType.INSERT) { 365 if (offset >= modOffset) { 366 offset += evt.getLength(); 367 } 368 } else if (evt.getType() == DocumentEvent.EventType.REMOVE) { 369 if (offset > modOffset) { 370 offset = Math.min(offset - evt.getLength(), modOffset); 371 } 372 } 373 return offset; 374 } 375 376 387 public static String getModificationText(DocumentEvent evt) { 388 return (String )getEventProperty(evt, String .class); 389 } 390 391 398 public static Element getParagraphElement(Document doc, int offset) { 399 Element paragraph; 400 if (doc instanceof StyledDocument ) { 401 paragraph = ((StyledDocument )doc).getParagraphElement(offset); 402 } else { 403 Element rootElem = doc.getDefaultRootElement(); 404 int index = rootElem.getElementIndex(offset); 405 paragraph = rootElem.getElement(index); 406 if ((offset < paragraph.getStartOffset()) || (offset >= paragraph.getEndOffset())) { 407 paragraph = null; 408 } 409 } 410 return paragraph; 411 } 412 413 419 public static Element getParagraphRootElement(Document doc) { 420 if (doc instanceof StyledDocument ) { 421 return ((StyledDocument )doc).getParagraphElement(0).getParentElement(); 422 } else { 423 return doc.getDefaultRootElement().getElement(0).getParentElement(); 424 } 425 } 426 427 431 private static final class DocumentCharSequence extends AbstractCharSequence.StringLike { 432 433 private final Segment segment = new Segment (); 434 435 private final Document doc; 436 437 DocumentCharSequence(Document doc) { 438 this.doc = doc; 439 } 440 441 public int length() { 442 return doc.getLength(); 443 } 444 445 public synchronized char charAt(int index) { 446 try { 447 doc.getText(index, 1, segment); 448 } catch (BadLocationException e) { 449 throw new IndexOutOfBoundsException (e.getMessage() 450 + " at offset=" + e.offsetRequested()); } 452 return segment.array[segment.offset]; 453 } 454 455 } 456 457 461 private static final class EventPropertiesElement implements Element { 462 463 static final EventPropertiesElement INSTANCE = new EventPropertiesElement(); 464 465 public int getStartOffset() { 466 return 0; 467 } 468 469 public int getEndOffset() { 470 return 0; 471 } 472 473 public int getElementCount() { 474 return 0; 475 } 476 477 public int getElementIndex(int offset) { 478 return -1; 479 } 480 481 public Element getElement(int index) { 482 return null; 483 } 484 485 public boolean isLeaf() { 486 return true; 487 } 488 489 public Element getParentElement() { 490 return null; 491 } 492 493 public String getName() { 494 return "Helper element for modification text providing"; } 496 497 public Document getDocument() { 498 return null; 499 } 500 501 public javax.swing.text.AttributeSet getAttributes() { 502 return null; 503 } 504 505 public String toString() { 506 return getName(); 507 } 508 509 } 510 511 private static final class EventPropertiesElementChange 512 implements DocumentEvent.ElementChange , UndoableEdit { 513 514 private CompactMap eventProperties = new CompactMap(); 515 516 public synchronized Object getProperty(Object key) { 517 return (eventProperties != null) ? eventProperties.get(key) : null; 518 } 519 520 @SuppressWarnings ("unchecked") 521 public synchronized Object putProperty(Object key, Object value) { 522 return eventProperties.put(key, value); 523 } 524 525 @SuppressWarnings ("unchecked") 526 public synchronized CompactMap.MapEntry putEntry(CompactMap.MapEntry entry) { 527 return eventProperties.putEntry(entry); 528 } 529 530 public int getIndex() { 531 return -1; 532 } 533 534 public Element getElement() { 535 return EventPropertiesElement.INSTANCE; 536 } 537 538 public Element [] getChildrenRemoved() { 539 return null; 540 } 541 542 public Element [] getChildrenAdded() { 543 return null; 544 } 545 546 public boolean replaceEdit(UndoableEdit anEdit) { 547 return false; 548 } 549 550 public boolean addEdit(UndoableEdit anEdit) { 551 return false; 552 } 553 554 public void undo() throws CannotUndoException { 555 } 557 558 public void redo() throws CannotRedoException { 559 } 561 562 public boolean isSignificant() { 563 return false; 564 } 565 566 public String getUndoPresentationName() { 567 return ""; 568 } 569 570 public String getRedoPresentationName() { 571 return ""; 572 } 573 574 public String getPresentationName() { 575 return ""; 576 } 577 578 public void die() { 579 } 581 582 public boolean canUndo() { 583 return true; 584 } 585 586 public boolean canRedo() { 587 return true; 588 } 589 590 } 591 592 } 593 | Popular Tags |