1 19 20 package org.netbeans.modules.properties; 21 22 import java.awt.EventQueue ; 23 import java.awt.Image ; 24 import java.beans.*; 25 import java.io.*; 26 import java.lang.ref.Reference ; 27 import java.lang.ref.WeakReference ; 28 import java.util.Collections ; 29 import java.util.Date ; 30 import java.util.Enumeration ; 31 import java.util.Set ; 32 import java.util.WeakHashMap ; 33 import javax.swing.JEditorPane ; 34 import javax.swing.JLabel ; 35 import javax.swing.text.BadLocationException ; 36 import javax.swing.text.Document ; 37 import javax.swing.text.EditorKit ; 38 import javax.swing.text.StyledDocument ; 39 import javax.swing.undo.CannotRedoException ; 40 import javax.swing.undo.CannotUndoException ; 41 import javax.swing.undo.UndoableEdit ; 42 import org.openide.DialogDisplayer; 43 import org.openide.ErrorManager; 44 import org.openide.NotifyDescriptor; 45 import org.openide.awt.UndoRedo; 46 import org.openide.cookies.CloseCookie; 47 import org.openide.cookies.EditCookie; 48 import org.openide.cookies.EditorCookie; 49 import org.openide.cookies.PrintCookie; 50 import org.openide.cookies.SaveCookie; 51 import org.openide.filesystems.FileChangeAdapter; 52 import org.openide.filesystems.FileEvent; 53 import org.openide.filesystems.FileLock; 54 import org.openide.filesystems.FileObject; 55 import org.openide.filesystems.FileStatusEvent; 56 import org.openide.filesystems.FileStatusListener; 57 import org.openide.filesystems.FileSystem; 58 import org.openide.filesystems.FileStateInvalidException; 59 import org.openide.filesystems.FileUtil; 60 import org.openide.loaders.DataObject; 61 import org.openide.nodes.Node; 62 import org.openide.text.CloneableEditor; 63 import org.openide.text.CloneableEditorSupport; 64 import org.openide.util.HelpCtx; 65 import org.openide.util.Mutex; 66 import org.openide.util.NbBundle; 67 import org.openide.util.WeakListeners; 68 import org.openide.util.Utilities; 69 import org.openide.windows.CloneableOpenSupport; 70 import org.openide.util.Task; 71 import org.openide.util.TaskListener; 72 import org.openide.windows.TopComponent; 73 74 80 public class PropertiesEditorSupport extends CloneableEditorSupport 81 implements EditCookie, EditorCookie.Observable, PrintCookie, CloseCookie, Serializable { 82 83 84 static final String PROP_NON_ASCII_CHAR_READ = "org.netbeans.modules.properties.nonAsciiPresent"; 86 private static final byte NEW_LINE_N = 0; 87 88 private static final byte NEW_LINE_R = 1; 89 90 private static final byte NEW_LINE_RN = 2; 91 92 93 private FileStatusListener fsStatusListener; 94 95 96 private byte newLineType = NEW_LINE_N; 97 98 99 transient PropertiesFileEntry myEntry; 100 101 102 static final long serialVersionUID =1787354011149868490L; 103 104 105 106 public PropertiesEditorSupport(PropertiesFileEntry entry) { 107 super(new Environment(entry), 108 org.openide.util.lookup.Lookups.singleton(entry.getDataObject())); 109 this.myEntry = entry; 110 } 111 112 118 protected boolean canClose () { 119 if (hasOpenedTableComponent()){ 121 return true; 122 }else{ 123 DataObject propDO = myEntry.getDataObject(); 124 if (propDO == null || !propDO.isModified()) return true; 125 return super.canClose(); 126 } 127 } 128 129 133 protected CloneableEditor createCloneableEditor() { 134 return new PropertiesEditor(this); 135 } 136 137 140 final class FsStatusListener implements FileStatusListener, Runnable { 141 142 144 public void annotationChanged(FileStatusEvent ev) { 145 if (ev.isNameChange() && ev.hasChanged(myEntry.getFile())) { 146 Mutex.EVENT.writeAccess(this); 147 } 148 } 149 150 152 public void run() { 153 updateEditorDisplayNames(); 154 } 155 } 156 157 159 private void attachStatusListener() { 160 if (fsStatusListener != null) { 161 return; } 163 164 FileSystem fs; 165 try { 166 fs = myEntry.getFile().getFileSystem(); 167 } catch (FileStateInvalidException ex) { 168 ErrorManager.getDefault().notify(ErrorManager.ERROR, ex); 169 return; 170 } 171 172 fsStatusListener = new FsStatusListener(); 173 fs.addFileStatusListener( 174 FileUtil.weakFileStatusListener(fsStatusListener, fs)); 175 } 176 177 179 private void updateEditorDisplayNames() { 180 assert EventQueue.isDispatchThread(); 181 182 final String title = messageName(); 183 final String htmlTitle = messageHtmlName(); 184 Enumeration en = allEditors.getComponents(); 185 while (en.hasMoreElements()) { 186 TopComponent tc = (TopComponent) en.nextElement(); 187 tc.setDisplayName(title); 188 tc.setHtmlDisplayName(htmlTitle); 189 } 190 } 191 192 194 protected void initializeCloneableEditor(CloneableEditor editor) { 195 ((PropertiesEditor) editor).initialize(myEntry); 196 } 197 198 205 protected StyledDocument createStyledDocument(EditorKit kit) { 206 StyledDocument document = super.createStyledDocument(kit); 207 208 document.putProperty(Document.TitleProperty, myEntry.getFile().toString()); 211 212 document.putProperty(Document.StreamDescriptionProperty, myEntry.getDataObject()); 214 215 document.addDocumentListener(new javax.swing.event.DocumentListener () { 218 public void insertUpdate(javax.swing.event.DocumentEvent e) { changed();} 219 public void changedUpdate(javax.swing.event.DocumentEvent e) { changed();} 220 public void removeUpdate(javax.swing.event.DocumentEvent e) { changed();} 221 private void changed() { 222 myEntry.getHandler().autoParse(); 223 } 224 }); 225 226 return document; 227 } 228 229 239 protected void loadFromStreamToKit(StyledDocument document, InputStream inputStream, EditorKit editorKit) 240 throws IOException, BadLocationException { 241 NewLineReader newLineReader = new NewLineReader(inputStream); 242 243 try { 244 editorKit.read(newLineReader, document, 0); 245 newLineType = newLineReader.getNewLineType(); 246 if (newLineReader.wasNonAsciiCharacterRead()) { 247 document.putProperty(PROP_NON_ASCII_CHAR_READ, Boolean.TRUE); 248 } 249 } finally { 250 newLineReader.close(); 251 } 252 } 253 254 264 protected void saveFromKitToStream(StyledDocument document, EditorKit editorKit, OutputStream outputStream) 265 throws IOException, BadLocationException { 266 Writer writer = new NewLineWriter(outputStream, newLineType); 267 268 try { 269 editorKit.write(writer, document, 0, document.getLength()); 270 } finally { 271 writer.flush(); 272 writer.close(); 273 } 274 } 275 276 281 protected boolean notifyModified () { 282 myEntry.getHandler().autoParse(); 284 285 if (super.notifyModified()) { 286 ((Environment)env).addSaveCookie(); 287 288 return true; 289 } else { 290 return false; 291 } 292 } 293 294 protected Task reloadDocument(){ 295 Task tsk = super.reloadDocument(); 296 tsk.addTaskListener(new TaskListener(){ 297 public void taskFinished(Task task){ 298 myEntry.getHandler().autoParse(); 299 } 300 }); 301 return tsk; 302 } 303 304 305 protected void notifyUnmodified () { 306 super.notifyUnmodified(); 307 308 ((Environment)env).removeSaveCookie(); 309 } 310 311 313 public void open() { 314 super.open(); 315 attachStatusListener(); 316 } 317 318 319 protected void notifyClosed() { 320 if(!hasOpenedTableComponent()) { 322 boolean wasModified = isModified(); 323 super.notifyClosed(); 324 if (wasModified) { 325 if(myEntry.getFile().isValid() && !myEntry.getFile().isVirtual()) { 327 myEntry.getHandler().reparseNowBlocking(); 328 } 329 } 330 } 331 } 332 333 338 protected String messageOpening() { 339 String name = myEntry.getDataObject().getPrimaryFile().getName()+"("+Util.getLocaleLabel(myEntry)+")"; 341 return NbBundle.getMessage( 342 PropertiesEditorSupport.class, 343 "LBL_ObjectOpen", name 345 ); 346 } 347 348 353 protected String messageOpened() { 354 String name = myEntry.getDataObject().getPrimaryFile().getName()+"("+Util.getLocaleLabel(myEntry)+")"; 356 return NbBundle.getMessage( 357 PropertiesEditorSupport.class, 358 "LBL_ObjectOpened", name 360 ); 361 } 362 363 365 private String getRawMessageName() { 366 return myEntry.getDataObject().getName() 367 + '(' + Util.getLocaleLabel(myEntry) + ')'; 368 } 369 370 372 private String addModifiedInfo(String name) { 373 int version = isModified() ? (myEntry.getFile().canWrite() ? 1 : 2) 374 : (myEntry.getFile().canWrite() ? 3 : 0); 375 return NbBundle.getMessage(PropertiesEditorSupport.class, 376 "LBL_EditorName", new Integer (version), 378 name); 379 } 380 381 386 protected String messageName () { 387 if (!myEntry.getDataObject().isValid()) { 388 return ""; } 390 391 return addModifiedInfo(getRawMessageName()); 392 } 393 394 395 protected String messageHtmlName () { 396 if (!myEntry.getDataObject().isValid()) { 397 return null; 398 } 399 400 String rawName = getRawMessageName(); 401 402 String annotatedName = null; 403 final FileObject entry = myEntry.getFile(); 404 try { 405 FileSystem.Status status = entry.getFileSystem().getStatus(); 406 if (status != null) { 407 Set <FileObject> files = Collections.singleton(entry); 408 if (status instanceof FileSystem.HtmlStatus) { 409 FileSystem.HtmlStatus hStatus = (FileSystem.HtmlStatus) 410 status; 411 annotatedName = hStatus.annotateNameHtml(rawName, files); 412 if (rawName.equals(annotatedName)) { 413 annotatedName = null; 414 } 415 if ((annotatedName != null) 416 && (!annotatedName.startsWith("<html>"))) { annotatedName = "<html>" + annotatedName; } 419 } 420 if (annotatedName == null) { 421 annotatedName = status.annotateName(rawName, files); 422 } 423 } 424 } catch (FileStateInvalidException ex) { 425 } 427 428 String name = (annotatedName != null) ? annotatedName : rawName; 429 return addModifiedInfo(name); 430 } 431 432 437 protected String messageSave () { 438 String name = myEntry.getDataObject().getPrimaryFile().getName()+"("+Util.getLocaleLabel(myEntry)+")"; 440 return NbBundle.getMessage ( 441 PropertiesEditorSupport.class, 442 "MSG_SaveFile", name 444 ); 445 } 446 447 452 protected String messageToolTip () { 453 FileObject fo = myEntry.getFile(); 455 return FileUtil.getFileDisplayName(fo); 456 } 457 458 460 protected UndoRedo.Manager createUndoRedoManager () { 461 return new UndoRedoStampFlagManager(); 462 } 463 464 469 UndoRedo.Manager getUndoRedoManager() { 470 return super.getUndoRedo(); 471 } 472 473 477 void forceNotifyClosed() { 478 super.notifyClosed(); 479 } 480 481 483 byte getNewLineType() { 484 return newLineType; 485 } 486 487 488 private void saveThisEntry() throws IOException { 489 super.saveDocument(); 490 if (!env.isModified()) { 494 myEntry.setModified(false); 495 } 496 } 497 498 500 public synchronized boolean hasOpenedTableComponent() { 501 return ((PropertiesDataObject)myEntry.getDataObject()).getOpenSupport().hasOpenedTableComponent(); 502 } 503 504 507 public synchronized boolean hasOpenedEditorComponent() { 508 Enumeration en = allEditors.getComponents (); 509 return en.hasMoreElements (); 510 } 511 512 513 private static final class Env extends Environment { 514 515 static final long serialVersionUID = -9218186467757330339L; 516 517 518 private PropertiesFileEntry entry; 519 520 521 public Env(PropertiesFileEntry entry) { 522 super(entry); 523 } 524 525 526 private void readObject(java.io.ObjectInputStream in) 527 throws IOException, ClassNotFoundException { 528 in.defaultReadObject(); 529 530 if(this.entry != null) 531 super.entry = this.entry; 532 } 533 } 534 535 536 537 private static class Environment implements CloneableEditorSupport.Env, 538 PropertyChangeListener, SaveCookie { 539 540 541 static final long serialVersionUID = 354528097109874355L; 542 543 544 protected PropertiesFileEntry entry; 545 546 547 private transient FileLock fileLock; 548 549 550 private transient PropertyChangeSupport propSupp; 551 552 553 private transient VetoableChangeSupport vetoSupp; 554 555 556 559 public Environment (PropertiesFileEntry entry) { 560 this.entry = entry; 561 entry.getFile().addFileChangeListener(new EnvironmentListener(this)); 562 entry.addPropertyChangeListener(this); 563 } 564 565 566 public void addPropertyChangeListener(PropertyChangeListener l) { 567 prop().addPropertyChangeListener (l); 568 } 569 570 571 572 public void propertyChange(PropertyChangeEvent evt) { 573 if(DataObject.PROP_VALID.equals(evt.getPropertyName ())) { 575 if(Boolean.FALSE.equals(evt.getOldValue())) return; 577 578 PropertiesEditorSupport support = (PropertiesEditorSupport)findCloneableOpenSupport(); 580 if(support != null) { 581 582 unmarkModified(); 585 586 support.close(false); 587 } 588 } else { 589 firePropertyChange ( 590 evt.getPropertyName(), 591 evt.getOldValue(), 592 evt.getNewValue() 593 ); 594 } 595 } 596 597 598 public void removePropertyChangeListener(PropertyChangeListener l) { 599 prop().removePropertyChangeListener (l); 600 } 601 602 603 public void addVetoableChangeListener(VetoableChangeListener l) { 604 veto().addVetoableChangeListener (l); 605 } 606 607 608 public void removeVetoableChangeListener(VetoableChangeListener l) { 609 veto().removeVetoableChangeListener (l); 610 } 611 612 618 public CloneableOpenSupport findCloneableOpenSupport() { 619 return (PropertiesEditorSupport)entry.getCookieSet().getCookie(EditCookie.class); 620 } 621 622 629 public boolean isValid() { 630 return entry.getDataObject().isValid(); 631 } 632 633 638 public boolean isModified() { 639 return entry.isModified(); 640 } 641 642 650 public void markModified() throws java.io.IOException { 651 if (fileLock == null || !fileLock.isValid()) { 652 fileLock = entry.takeLock(); 653 } 654 655 entry.setModified(true); 656 } 657 658 663 public void unmarkModified() { 664 if (fileLock != null && fileLock.isValid()) { 665 fileLock.releaseLock(); 666 } 667 668 entry.setModified(false); 669 } 670 671 676 public String getMimeType() { 677 return entry.getFile().getMIMEType(); 678 } 679 680 683 public Date getTime() { 684 entry.getFile().refresh(false); 686 return entry.getFile().lastModified(); 687 } 688 689 694 public InputStream inputStream() throws IOException { 695 return entry.getFile().getInputStream(); 696 } 697 698 703 public OutputStream outputStream() throws IOException { 704 return entry.getFile().getOutputStream(fileLock); 705 } 706 707 712 public void save() throws IOException { 713 ((PropertiesEditorSupport)findCloneableOpenSupport()).saveThisEntry(); 715 } 716 717 722 private void firePropertyChange (String name, Object oldValue, Object newValue) { 723 prop().firePropertyChange (name, oldValue, newValue); 724 } 725 726 731 private void fireVetoableChange (String name, Object oldValue, Object newValue) throws PropertyVetoException { 732 veto ().fireVetoableChange (name, oldValue, newValue); 733 } 734 735 736 private PropertyChangeSupport prop() { 737 if (propSupp == null) { 738 synchronized (this) { 739 if (propSupp == null) { 740 propSupp = new PropertyChangeSupport (this); 741 } 742 } 743 } 744 745 return propSupp; 746 } 747 748 749 private VetoableChangeSupport veto() { 750 if (vetoSupp == null) { 751 synchronized (this) { 752 if (vetoSupp == null) { 753 vetoSupp = new VetoableChangeSupport (this); 754 } 755 } 756 } 757 return vetoSupp; 758 } 759 760 761 private void addSaveCookie() { 762 if (entry.getCookie(SaveCookie.class) == null) { 763 entry.getCookieSet().add(this); 764 } 765 ((PropertiesDataObject)entry.getDataObject()).updateModificationStatus(); 766 } 767 768 769 private void removeSaveCookie() { 770 SaveCookie sc = (SaveCookie)entry.getCookie(SaveCookie.class); 772 773 if (sc != null && sc.equals(this)) { 774 entry.getCookieSet().remove(this); 775 } 776 777 PropertiesRequestProcessor.getInstance().post(new Runnable () { 778 public void run() { 779 ((PropertiesDataObject)entry.getDataObject()).updateModificationStatus(); 780 } 781 }); 782 } 783 784 788 private void fileChanged(boolean expected, long time) { 789 if (expected) { 790 firePropertyChange (PROP_TIME, null, null); 792 } else { 793 firePropertyChange (PROP_TIME, null, new Date (time)); 794 } 795 } 796 797 798 801 private void fileRemoved() { 802 try { 803 fireVetoableChange(PROP_VALID, Boolean.TRUE, Boolean.FALSE); 804 } catch(PropertyVetoException pve) { 805 } 807 808 firePropertyChange(PROP_VALID, Boolean.TRUE, Boolean.FALSE); 809 } 810 } 812 813 815 private static final class EnvironmentListener extends FileChangeAdapter { 816 817 818 private Reference <Environment> reference; 819 820 822 public EnvironmentListener(Environment environment) { 823 reference = new WeakReference <Environment>(environment); 824 } 825 826 829 public void fileChanged(FileEvent evt) { 830 Environment environment = reference.get(); 831 if (environment != null) { 832 if(!environment.entry.getFile().equals(evt.getFile()) ) { 833 evt.getFile().removeFileChangeListener(this); 836 environment.entry.getFile().addFileChangeListener(new EnvironmentListener(environment)); 838 return; 839 } 840 841 if(evt.getFile().isVirtual()) { 843 environment.entry.getFile().removeFileChangeListener(this); 844 environment.fileRemoved(); 847 environment.entry.getFile().addFileChangeListener(this); 848 } else { 849 environment.fileChanged(evt.isExpected(), evt.getTime()); 850 } 851 } 852 } 853 } 855 856 857 public class PropertiesEditAt implements EditCookie { 858 859 860 private String key; 861 862 863 864 PropertiesEditAt(String key) { 865 this.key = key; 866 } 867 868 869 870 public void setKey(String key) { 871 this.key = key; 872 } 873 874 875 public void edit() { 876 PropertiesEditor editor = (PropertiesEditor)PropertiesEditorSupport.super.openCloneableTopComponent(); 877 editor.requestActive(); 878 879 Element.ItemElem item = myEntry.getHandler().getStructure().getItem(key); 880 if (item != null) { 881 int offset = item.getKeyElem().getBounds().getBegin().getOffset(); 882 if (editor.getPane() != null && editor.getPane().getCaret() !=null) 883 editor.getPane().getCaret().setDot(offset); 884 } 885 } 886 } 888 889 890 public static class PropertiesEditor extends CloneableEditor 891 implements Runnable { 892 893 894 protected transient PropertiesFileEntry entry; 895 896 897 private transient PropertyChangeListener saveCookieLNode; 898 899 900 private transient boolean hasBeenActivated = false; 901 902 903 static final long serialVersionUID =-2702087884943509637L; 904 905 906 907 public PropertiesEditor() { 908 super(); 909 } 910 911 912 public PropertiesEditor(PropertiesEditorSupport support) { 913 super(support); 914 } 915 916 917 918 private void initialize(PropertiesFileEntry entry) { 919 this.entry = entry; 920 921 Node n = entry.getNodeDelegate (); 922 setActivatedNodes (new Node[] { n }); 923 924 updateName(); 925 926 saveCookieLNode = new PropertyChangeListener() { 928 public void propertyChange(PropertyChangeEvent evt) { 929 if (Node.PROP_COOKIE.equals(evt.getPropertyName()) || 930 DataObject.PROP_NAME.equals(evt.getPropertyName())) { 931 PropertiesEditor.super.updateName(); 932 } 933 } 934 }; 935 this.entry.addPropertyChangeListener( 936 WeakListeners.propertyChange(saveCookieLNode, this.entry)); 937 } 938 939 941 protected void componentActivated() { 942 super.componentActivated(); 943 if (!hasBeenActivated) { 944 hasBeenActivated = true; 945 if (Boolean.TRUE.equals(getEditorPane().getDocument().getProperty( 946 PROP_NON_ASCII_CHAR_READ))) { 947 EventQueue.invokeLater(this); 948 } 949 } 950 } 951 952 954 public void run() { 955 String msg = NbBundle.getMessage(getClass(), 956 "MSG_OnlyLatin1Supported"); Object msgObject; 958 int nlIndex = msg.indexOf('\n'); 959 if (nlIndex == -1) { 960 msgObject = msg; 961 } else { 962 StringBuilder buf = new StringBuilder (msg.length() + 40); 963 buf.append("<html>"); 965 int lastNlIndex = -1; 966 do { 967 buf.append(msg.substring(lastNlIndex + 1, nlIndex)); 968 buf.append("<br>"); lastNlIndex = nlIndex; 970 nlIndex = msg.indexOf('\n', lastNlIndex + 1); 971 } while (nlIndex != -1); 972 buf.append(msg.substring(lastNlIndex + 1)); 973 msgObject = new JLabel (buf.toString()); 974 } 975 976 DialogDisplayer.getDefault().notify( 977 new NotifyDescriptor.Message( 978 msgObject, 979 NotifyDescriptor.WARNING_MESSAGE)); 980 } 981 982 987 protected boolean closeLast () { 988 return super.closeLast(); 989 } 990 991 992 public Image getIcon () { 993 return Utilities.loadImage("org/netbeans/modules/properties/propertiesLocale.gif"); } 995 996 997 public HelpCtx getHelpCtx() { 998 return new HelpCtx(Util.HELP_ID_EDITLOCALE); 999 } 1000 1001 1002 private JEditorPane getPane() { 1003 return pane; 1004 } 1005 } 1007 1008 1009 static class NewLineReader extends BufferedReader { 1010 1011 1012 int[] newLineTypes; 1013 1014 private boolean nonAsciiCharacterRead = false; 1015 1016 1017 1023 public NewLineReader(InputStream is) throws IOException { 1024 super(new InputStreamReader(is, "8859_1")); 1026 newLineTypes = new int[] { 0, 0, 0 }; 1027 } 1028 1029 1030 1034 public int read() throws IOException { 1035 int nextToRead = super.read(); 1036 1037 if (nextToRead == -1) 1038 return -1; 1039 1040 if (nextToRead == '\r') { 1041 nextToRead = super.read(); 1042 1043 while (nextToRead == '\r') 1044 nextToRead = super.read(); 1045 if (nextToRead == '\n') { 1046 nextToRead = super.read(); 1047 newLineTypes[NEW_LINE_RN]++; 1048 return '\n'; 1049 } else { 1050 newLineTypes[NEW_LINE_R]++; 1051 return '\n'; 1052 } 1053 } 1054 if (nextToRead == '\n') { 1055 nextToRead = super.read(); 1056 newLineTypes[NEW_LINE_N]++; 1057 return '\n'; 1058 } 1059 if (nextToRead > 0x7e) { 1060 nonAsciiCharacterRead = true; 1061 } 1062 1063 return nextToRead; 1064 } 1065 1066 1069 public int read(char cbuf[], int off, int len) throws IOException { 1070 int charsCount = super.read(cbuf, off, len); 1071 if (!nonAsciiCharacterRead && (charsCount > 0)) { 1072 final int upperLimit = off + len; 1073 for (int i = off; i < upperLimit; i++) { 1074 if (cbuf[i] > 0x7e) { 1075 nonAsciiCharacterRead = true; 1076 break; 1077 } 1078 } 1079 } 1080 return charsCount; 1081 } 1082 1083 1084 public byte getNewLineType() { 1085 if (newLineTypes[0] > newLineTypes[1]) { 1086 return (newLineTypes[0] > newLineTypes[2]) ? NEW_LINE_N : NEW_LINE_RN; 1087 } else { 1088 return (newLineTypes[1] > newLineTypes[2]) ? NEW_LINE_R : NEW_LINE_RN; 1089 } 1090 } 1091 1092 1094 public boolean wasNonAsciiCharacterRead() { 1095 return nonAsciiCharacterRead; 1096 } 1097 1098 } 1100 1101 1103 static class NewLineWriter extends BufferedWriter { 1104 1105 1106 byte newLineType; 1107 1108 1109 1113 public NewLineWriter(OutputStream stream, byte newLineType) throws UnsupportedEncodingException { 1114 super(new OutputStreamWriter(stream, "8859_1")); 1115 1116 this.newLineType = newLineType; 1117 } 1118 1119 1120 1123 public void write(int character) throws IOException { 1124 if(character == '\r') 1125 return; 1127 if(character == '\n') { 1128 if(newLineType == NEW_LINE_R) { 1129 super.write('\r'); 1131 } else if(newLineType == NEW_LINE_N) { 1132 super.write('\n'); 1134 } else if(newLineType == NEW_LINE_RN) { 1135 super.write('\r'); 1137 super.write('\n'); 1138 } 1139 } else { 1140 super.write(character); 1141 } 1142 } 1143 1144 } 1146 1147 1150 class UndoRedoStampFlagManager extends UndoRedo.Manager { 1151 1152 1153 WeakHashMap <UndoableEdit ,StampFlag> stampFlags 1154 = new WeakHashMap <UndoableEdit ,StampFlag>(5); 1155 1156 1157 public synchronized boolean addEdit(UndoableEdit anEdit) { 1158 stampFlags.put(anEdit, new StampFlag(System.currentTimeMillis(), 1159 ((PropertiesDataObject)PropertiesEditorSupport.this.myEntry.getDataObject()).getOpenSupport().atomicUndoRedoFlag )); 1160 return super.addEdit(anEdit); 1161 } 1162 1163 1164 public boolean replaceEdit(UndoableEdit anEdit) { 1165 stampFlags.put(anEdit, new StampFlag(System.currentTimeMillis(), 1166 ((PropertiesDataObject)PropertiesEditorSupport.this.myEntry.getDataObject()).getOpenSupport().atomicUndoRedoFlag )); 1167 return super.replaceEdit(anEdit); 1168 } 1169 1170 1171 public synchronized void undo() throws CannotUndoException { 1172 UndoableEdit anEdit = editToBeUndone(); 1173 if(anEdit != null) { 1174 Object atomicFlag = stampFlags.get(anEdit).getAtomicFlag(); super.undo(); 1176 stampFlags.put(anEdit, new StampFlag(System.currentTimeMillis(), atomicFlag)); 1177 } 1178 } 1179 1180 1181 public synchronized void redo() throws CannotRedoException { 1182 UndoableEdit anEdit = editToBeRedone(); 1183 if(anEdit != null) { 1184 Object atomicFlag = stampFlags.get(anEdit).getAtomicFlag(); super.redo(); 1186 stampFlags.put(anEdit, new StampFlag(System.currentTimeMillis(), atomicFlag)); 1187 } 1188 } 1189 1190 1192 public long getTimeStampOfEditToBeUndone() { 1193 UndoableEdit nextUndo = editToBeUndone(); 1194 if (nextUndo == null) { 1195 return 0L; 1196 } else { 1197 return stampFlags.get(nextUndo).getTimeStamp(); 1198 } 1199 } 1200 1201 1203 public long getTimeStampOfEditToBeRedone() { 1204 UndoableEdit nextRedo = editToBeRedone(); 1205 if (nextRedo == null) { 1206 return 0L; 1207 } else { 1208 return stampFlags.get(nextRedo).getTimeStamp(); 1209 } 1210 } 1211 1212 1214 public Object getAtomicFlagOfEditToBeUndone() { 1215 UndoableEdit nextUndo = editToBeUndone(); 1216 if (nextUndo == null) { 1217 return null; 1218 } else { 1219 return (stampFlags.get(nextUndo)).getAtomicFlag(); 1220 } 1221 } 1222 1223 1225 public Object getAtomicFlagOfEditToBeRedone() { 1226 UndoableEdit nextRedo = editToBeRedone(); 1227 if (nextRedo == null) { 1228 return null; 1229 } else { 1230 return (stampFlags.get(nextRedo)).getAtomicFlag(); 1231 } 1232 } 1233 1234 } 1236 1239 static class StampFlag { 1240 1241 1243 private long timeStamp; 1244 1245 1249 private Object atomicFlag; 1250 1251 1252 public StampFlag(long timeStamp, Object atomicFlag) { 1253 this.timeStamp = timeStamp; 1254 this.atomicFlag = atomicFlag; 1255 } 1256 1257 1258 public long getTimeStamp() { 1259 return timeStamp; 1260 } 1261 1262 1263 public void setTimeStamp(long timeStamp) { 1264 this.timeStamp = timeStamp; 1265 } 1266 1267 1269 public Object getAtomicFlag() { 1270 return atomicFlag; 1271 } 1272 } } 1274 | Popular Tags |