1 19 20 21 package org.netbeans.modules.html; 22 import java.io.IOException ; 23 import java.io.InputStream ; 24 import java.io.ObjectInput ; 25 import java.io.OutputStream ; 26 import java.io.ByteArrayInputStream ; 27 import java.io.SequenceInputStream ; 28 import java.io.InputStreamReader ; 29 import java.io.UnsupportedEncodingException ; 30 import java.io.OutputStreamWriter ; 31 import javax.swing.text.EditorKit ; 32 import javax.swing.text.StyledDocument ; 33 import javax.swing.text.BadLocationException ; 34 import org.netbeans.api.html.lexer.HTMLTokenId; 35 import org.netbeans.api.lexer.Token; 36 import org.netbeans.api.lexer.TokenHierarchy; 37 import org.netbeans.api.lexer.TokenSequence; 38 import org.netbeans.modules.html.palette.HTMLPaletteFactory; 39 import org.netbeans.spi.palette.PaletteController; 40 import org.openide.ErrorManager; 41 import org.openide.cookies.EditCookie; 42 import org.openide.cookies.EditorCookie; 43 import org.openide.cookies.OpenCookie; 44 import org.openide.cookies.PrintCookie; 45 import org.openide.cookies.SaveCookie; 46 import org.openide.filesystems.FileObject; 47 import org.openide.filesystems.FileLock; 48 import org.openide.loaders.DataObject; 49 import org.openide.nodes.Node; 50 import org.openide.nodes.Node.Cookie; 51 import org.openide.text.CloneableEditor; 52 import org.openide.text.DataEditorSupport; 53 import org.openide.util.Lookup; 54 import org.openide.util.NbBundle; 55 import org.openide.util.lookup.AbstractLookup; 56 import org.openide.util.lookup.InstanceContent; 57 import org.openide.util.lookup.ProxyLookup; 58 import org.openide.windows.CloneableOpenSupport; 59 60 61 62 68 public final class HtmlEditorSupport extends DataEditorSupport implements OpenCookie, EditCookie, EditorCookie.Observable, PrintCookie { 69 70 private static final String CHARSET_DECL = "CHARSET="; private static final String HEAD_END_TAG_NAME = "</HEAD>"; 74 75 77 private final SaveCookie saveCookie = new SaveCookie() { 78 79 public void save() throws IOException { 80 HtmlEditorSupport.this.saveDocument(); 81 HtmlEditorSupport.this.getDataObject().setModified(false); 82 } 83 }; 84 85 86 87 HtmlEditorSupport(HtmlDataObject obj) { 88 super(obj, new Environment(obj)); 89 90 setMIMEType("text/html"); } 92 93 98 protected boolean notifyModified () { 99 if (!super.notifyModified()) 100 return false; 101 102 addSaveCookie(); 103 104 return true; 105 } 106 107 108 protected void notifyUnmodified () { 109 super.notifyUnmodified(); 110 111 removeSaveCookie(); 112 } 113 114 115 private void addSaveCookie() { 116 HtmlDataObject obj = (HtmlDataObject)getDataObject(); 117 118 if(obj.getCookie(SaveCookie.class) == null) { 120 obj.getCookieSet0().add(saveCookie); 121 obj.setModified(true); 122 } 123 } 124 125 126 private void removeSaveCookie() { 127 HtmlDataObject obj = (HtmlDataObject)getDataObject(); 128 129 Cookie cookie = obj.getCookie(SaveCookie.class); 131 132 if(cookie != null && cookie.equals(saveCookie)) { 133 obj.getCookieSet0().remove(saveCookie); 134 obj.setModified(false); 135 } 136 } 137 138 148 protected void loadFromStreamToKit(StyledDocument doc, InputStream stream, EditorKit kit) throws IOException , BadLocationException { 149 byte[] arr = new byte[4096]; 150 int len = stream.read (arr, 0, arr.length); 151 String txt = new String (arr, 0, (len>=0)?len:0).toUpperCase(); 152 txt = findEncoding (txt); 154 155 if (len < arr.length) { 157 stream = new ByteArrayInputStream (arr, 0, len); 158 } else { 159 stream = new SequenceInputStream ( 160 new ByteArrayInputStream (arr), stream 161 ); 162 } 163 164 if (txt != null) { 165 try { 166 InputStreamReader r = new InputStreamReader (stream, txt); 167 kit.read (r, doc, 0); 168 return; 169 } catch (UnsupportedEncodingException ex) { 170 } catch (Exception ex) { 172 ErrorManager.getDefault ().annotate ( 174 ex, NbBundle.getMessage(HtmlEditorSupport.class, "MSG_errorInReadingWithEnc", 175 getDataObject().getPrimaryFile().getPath(),txt) 176 ); 177 ErrorManager.getDefault ().notify (ErrorManager.INFORMATIONAL, ex); 178 } 179 180 } 181 182 kit.read (stream, doc, 0); 184 } 185 186 194 protected void saveFromKitToStream(StyledDocument doc, EditorKit kit, OutputStream stream) throws IOException , BadLocationException { 195 int len = doc.getLength(); 196 if (len > 4096) { 197 len = 4096; 198 } 199 String txt = doc.getText(0, len).toUpperCase(); 200 txt = findEncoding (txt); 202 203 if (txt != null) { 204 try { 206 OutputStreamWriter w = new OutputStreamWriter (stream, txt); 207 kit.write (w, doc, 0, doc.getLength()); 208 return; 209 } catch (UnsupportedEncodingException ex) { 210 } 212 } 213 214 super.saveFromKitToStream(doc, kit, stream); 216 } 217 218 223 private static String findEncoding (String txt) { 224 int headEndOffset = txt.indexOf (HEAD_END_TAG_NAME); headEndOffset = headEndOffset == -1 ? txt.indexOf(HEAD_END_TAG_NAME.toLowerCase()) : headEndOffset; 226 227 if (headEndOffset == -1){ 228 return null; 229 } 230 231 TokenHierarchy hi = TokenHierarchy.create(txt, HTMLTokenId.language()); 232 TokenSequence ts = hi.tokenSequence(); 233 ts.moveStart(); 234 while(ts.moveNext()) { 235 Token token = ts.token(); 236 237 if(token.offset(hi) >= headEndOffset) { 239 break; 240 } 241 242 if(token.id() == HTMLTokenId.VALUE) { 243 String tokenImage = token.text().toString(); 244 int charsetOffset = tokenImage.indexOf(CHARSET_DECL); 245 charsetOffset = charsetOffset == -1 ? tokenImage.indexOf(CHARSET_DECL.toLowerCase()) : charsetOffset; 246 247 int charsetEndOffset = charsetOffset + CHARSET_DECL.length(); 248 if (charsetOffset != -1){ 249 int endOffset = tokenImage.indexOf('"', charsetEndOffset); 250 251 if (endOffset == -1){ 252 endOffset = tokenImage.indexOf('\'', charsetEndOffset); 253 } 254 255 if (endOffset == -1){ 256 endOffset = tokenImage.indexOf(';', charsetEndOffset); 257 } 258 259 if (endOffset == -1){ 260 return null; 261 } 262 263 String encoding = tokenImage.substring(charsetEndOffset, endOffset); 264 return encoding; 265 } 266 } 267 } 268 269 return null; } 271 272 273 private static class Environment extends DataEditorSupport.Env { 274 275 private static final long serialVersionUID = 3035543168452715818L; 276 277 278 public Environment(HtmlDataObject obj) { 279 super(obj); 280 } 281 282 283 284 protected FileObject getFile() { 285 return getDataObject().getPrimaryFile(); 286 } 287 288 289 protected FileLock takeLock() throws IOException { 290 return ((HtmlDataObject)getDataObject()).getPrimaryEntry().takeLock(); 291 } 292 293 297 public CloneableOpenSupport findCloneableOpenSupport() { 298 return (HtmlEditorSupport)getDataObject().getCookie(HtmlEditorSupport.class); 299 } 300 } 302 303 306 protected CloneableEditor createCloneableEditor() { 307 return new HtmlEditor(this); 308 } 309 310 public static class HtmlEditor extends CloneableEditor { 311 312 public HtmlEditor() { 313 } 314 315 void associatePalette(HtmlEditorSupport s) { 316 317 Node nodes[] = { s.getDataObject().getNodeDelegate() }; 318 InstanceContent instanceContent = new InstanceContent(); 319 associateLookup(new ProxyLookup(new Lookup[] { new AbstractLookup(instanceContent), nodes[0].getLookup()})); 320 instanceContent.add(getActionMap()); 321 322 setActivatedNodes(nodes); 323 324 DataObject dataObject = s.getDataObject(); 325 if (dataObject instanceof HtmlDataObject) { 326 try { 327 PaletteController pc = HTMLPaletteFactory.getPalette(); 328 instanceContent.add(pc); 329 } 330 catch (IOException ioe) { 331 ioe.printStackTrace(); 333 } 334 } 335 } 336 337 338 public HtmlEditor(HtmlEditorSupport s) { 339 super(s); 340 initialize(); 341 } 342 343 private void initialize() { 344 associatePalette((HtmlEditorSupport)cloneableEditorSupport()); 345 } 346 347 public void readExternal(ObjectInput in) throws IOException , ClassNotFoundException { 348 super.readExternal(in); 349 initialize(); 350 } 351 352 } 353 354 } 355 | Popular Tags |