1 19 20 package org.netbeans.modules.web.jsf; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.util.ArrayList ; 25 import javax.swing.SwingUtilities ; 26 import javax.swing.event.DocumentEvent ; 27 import javax.swing.event.DocumentListener ; 28 import javax.swing.text.BadLocationException ; 29 import org.netbeans.core.spi.multiview.MultiViewDescription; 30 import org.netbeans.core.spi.multiview.MultiViewFactory; 31 import org.netbeans.modules.web.jsf.api.editor.JSFConfigEditorContext; 32 import org.netbeans.modules.xml.api.EncodingUtil; 33 import org.openide.DialogDescriptor; 34 import org.openide.DialogDisplayer; 35 import org.openide.ErrorManager; 36 import org.openide.NotifyDescriptor; 37 import org.openide.awt.UndoRedo; 38 import org.openide.cookies.EditorCookie.Observable; 39 import org.openide.filesystems.FileLock; 40 import org.openide.filesystems.FileObject; 41 import org.openide.nodes.Node.Cookie; 42 import org.openide.text.CloneableEditorSupport.Pane; 43 import org.openide.text.DataEditorSupport; 44 import org.openide.cookies.*; 45 import org.openide.text.CloneableEditorSupport; 46 import org.openide.text.NbDocument; 47 import org.openide.util.NbBundle; 48 import org.openide.util.RequestProcessor; 49 import org.openide.windows.TopComponent; 50 51 55 public class JSFConfigEditorSupport extends DataEditorSupport 56 implements OpenCookie, EditCookie, EditorCookie.Observable, PrintCookie, CloseCookie { 57 58 60 private final SaveCookie saveCookie = new SaveCookie() { 61 62 public void save() throws java.io.IOException { 63 JSFConfigDataObject obj = (JSFConfigDataObject) getDataObject(); 64 restartTimer(); 66 obj.parsingDocument(); 67 68 if (obj.isDocumentValid()) { 69 saveDocument(); 70 }else { 71 DialogDescriptor dialog = new DialogDescriptor( 74 NbBundle.getMessage(JSFConfigEditorSupport.class, "MSG_invalidXmlWarning"), 75 NbBundle.getMessage(JSFConfigEditorSupport.class, "TTL_invalidXmlWarning")); 76 java.awt.Dialog d = org.openide.DialogDisplayer.getDefault().createDialog(dialog); 77 d.setVisible(true); 78 if (dialog.getValue() == org.openide.DialogDescriptor.OK_OPTION) { 79 saveDocument(); 80 } 81 88 } 89 } 90 }; 91 private JSFConfigDataObject dataObject; 92 private RequestProcessor.Task parsingDocumentTask; 93 private TopComponent mvtc; 94 95 96 private static final int AUTO_PARSING_DELAY = 2000; 97 98 public JSFConfigEditorSupport(JSFConfigDataObject dobj) { 99 super(dobj,new XmlEnv(dobj)); 100 dataObject = dobj; 101 setMIMEType("text/x-jsf+xml"); 103 initialize(); 105 } 106 107 @Override 108 protected Pane createPane() { 109 JSFConfigEditorContext context = new JSFConfigEditorContextImpl((JSFConfigDataObject)getDataObject()); 111 ArrayList <MultiViewDescription> descriptions = 112 new ArrayList <MultiViewDescription> (JSFConfigEditorViewFactorySupport.createViewDescriptions(context)); 113 if (descriptions.size() > 0) { 114 descriptions.add( new JSFConfigMultiviewDescriptor(context)); 115 return (CloneableEditorSupport.Pane) MultiViewFactory.createCloneableMultiView(descriptions.toArray(new MultiViewDescription[descriptions.size()]), descriptions.get(0), null); 116 } else { 117 return super.createPane(); 118 } 119 } 120 121 public UndoRedo.Manager getUndoRedoManager() { 122 return super.getUndoRedo(); 123 } 124 125 protected void setMVTC(TopComponent mvtc) { 126 this.mvtc = mvtc; 127 updateDisplayName(); 128 } 129 130 private int click = 0; 131 public void updateDisplayName() { 132 133 final TopComponent tc = mvtc; 134 if (tc == null) 135 return; 136 137 SwingUtilities.invokeLater(new Runnable () { 138 public void run() { 139 String displayName = messageName(); 140 141 if (! displayName.equals(tc.getDisplayName())){ 142 tc.setDisplayName(displayName); 143 } 144 tc.setToolTipText(dataObject.getPrimaryFile().getPath()); 145 } 146 }); 147 } 148 149 private void initialize() { 150 final DocumentListener docListener = new DocumentListener () { 152 public void insertUpdate(DocumentEvent e) { change(e); } 153 public void changedUpdate(DocumentEvent e) { } 154 public void removeUpdate(DocumentEvent e) { change(e); } 155 156 private void change(DocumentEvent e) { 157 if (!dataObject.isNodeDirty()) restartTimer(); 158 } 159 }; 160 addPropertyChangeListener(new PropertyChangeListener () { 162 public void propertyChange(PropertyChangeEvent evt) { 163 if (EditorCookie.Observable.PROP_DOCUMENT.equals(evt.getPropertyName()) 164 && isDocumentLoaded() && getDocument() != null) { 165 getDocument().addDocumentListener(docListener); 166 } 167 } 168 }); 169 } 170 171 175 public void saveDocument() throws java.io.IOException { 176 final javax.swing.text.StyledDocument doc = getDocument(); 177 String defaultEncoding = "UTF-8"; String enc = EncodingUtil.detectEncoding(doc); 180 boolean changeEncodingToDefault = false; 181 if (enc == null) enc = defaultEncoding; 182 183 if (!isSupportedEncoding(enc)){ 185 NotifyDescriptor nd = new NotifyDescriptor.Confirmation( 186 NbBundle.getMessage(JSFConfigEditorSupport.class, "MSG_BadEncodingDuringSave", new Object [] { getDataObject().getPrimaryFile().getNameExt(), 188 enc, 189 defaultEncoding} ), 190 NotifyDescriptor.YES_NO_OPTION, 191 NotifyDescriptor.WARNING_MESSAGE); 192 nd.setValue(NotifyDescriptor.NO_OPTION); 193 DialogDisplayer.getDefault().notify(nd); 194 if(nd.getValue() != NotifyDescriptor.YES_OPTION) return; 195 changeEncodingToDefault = true; 196 } 197 198 if (!changeEncodingToDefault){ 199 try { 201 java.nio.charset.CharsetEncoder coder = java.nio.charset.Charset.forName(enc).newEncoder(); 202 if (!coder.canEncode(doc.getText(0, doc.getLength()))){ 203 NotifyDescriptor nd = new NotifyDescriptor.Confirmation( 204 NbBundle.getMessage(JSFConfigEditorSupport.class, "MSG_BadCharConversion", new Object [] { getDataObject().getPrimaryFile().getNameExt(), 206 enc}), 207 NotifyDescriptor.YES_NO_OPTION, 208 NotifyDescriptor.WARNING_MESSAGE); 209 nd.setValue(NotifyDescriptor.NO_OPTION); 210 DialogDisplayer.getDefault().notify(nd); 211 if(nd.getValue() != NotifyDescriptor.YES_OPTION) return; 212 } 213 } catch (javax.swing.text.BadLocationException e){ 214 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 215 } 216 super.saveDocument(); 217 getDataObject().setModified(false); 219 } else { 220 222 try { 223 final int MAX_PROLOG = 1000; 224 int maxPrologLen = Math.min(MAX_PROLOG, doc.getLength()); 225 final char prolog[] = doc.getText(0, maxPrologLen).toCharArray(); 226 int prologLen = 0; 228 if (prolog[0] == '<' && prolog[1] == '?' && prolog[2] == 'x') { 230 231 for (int i = 3; i<maxPrologLen; i++) { 233 if (prolog[i] == '?' && prolog[i+1] == '>') { 234 prologLen = i + 1; 235 break; 236 } 237 } 238 } 239 240 final int passPrologLen = prologLen; 241 242 Runnable edit = new Runnable () { 243 public void run() { 244 try { 245 246 doc.remove(0, passPrologLen + 1); doc.insertString(0, "<?xml version='1.0' encoding='UTF-8' ?> \n<!-- was: " + new String (prolog, 0, passPrologLen + 1) + " -->", null); 249 } catch (BadLocationException e) { 250 if (System.getProperty("netbeans.debug.exceptions") != null) e.printStackTrace(); 252 } 253 } 254 }; 255 256 NbDocument.runAtomic(doc, edit); 257 258 super.saveDocument(); 259 getDataObject().setModified(false); 261 } catch (javax.swing.text.BadLocationException e){ 262 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); 263 } 264 } 265 } 266 267 private boolean isSupportedEncoding(String encoding){ 268 boolean supported; 269 try{ 270 supported = java.nio.charset.Charset.isSupported(encoding); 271 } catch (java.nio.charset.IllegalCharsetNameException e){ 272 supported = false; 273 } 274 275 return supported; 276 } 277 278 279 282 public void restartTimer() { 283 if (parsingDocumentTask==null || parsingDocumentTask.isFinished() || 284 parsingDocumentTask.cancel()) { 285 dataObject.setDocumentDirty(true); 286 Runnable r = new Runnable () { 287 public void run() { 288 dataObject.parsingDocument(); 289 } 290 }; 291 if (parsingDocumentTask != null) 292 parsingDocumentTask = RequestProcessor.getDefault().post(r, AUTO_PARSING_DELAY); 293 else 294 parsingDocumentTask = RequestProcessor.getDefault().post(r, 100); 295 } 296 } 297 298 303 protected boolean notifyModified() { 304 boolean notif = super.notifyModified(); 305 if (!notif){ 306 return false; 307 } 308 updateDisplayName(); 309 addSaveCookie(); 310 return true; 311 } 312 313 314 protected void notifyUnmodified() { 315 super.notifyUnmodified(); 316 updateDisplayName(); 317 removeSaveCookie(); 318 } 319 320 321 private void addSaveCookie() { 322 if(dataObject.getCookie(SaveCookie.class) == null) { 324 dataObject.getCookieSet0().add(saveCookie); 325 dataObject.setModified(true); 326 } 327 } 328 329 330 private void removeSaveCookie() { 331 JSFConfigDataObject obj = (JSFConfigDataObject)getDataObject(); 332 333 Cookie cookie = obj.getCookie(SaveCookie.class); 335 336 if(cookie != null && cookie.equals(saveCookie)) { 337 obj.getCookieSet0().remove(saveCookie); 338 obj.setModified(false); 339 } 340 } 341 342 public void open() { 343 super.open(); 344 restartTimer(); 346 updateDisplayName(); 347 } 348 349 350 private static class XmlEnv extends DataEditorSupport.Env { 351 352 private static final long serialVersionUID = -800036748848958489L; 353 354 356 359 public XmlEnv(JSFConfigDataObject obj) { 360 super(obj); 361 } 362 363 366 protected FileObject getFile() { 367 return getDataObject().getPrimaryFile(); 368 } 369 370 376 protected FileLock takeLock() throws java.io.IOException { 377 return ((JSFConfigDataObject) getDataObject()).getPrimaryEntry().takeLock(); 378 } 379 380 385 public org.openide.windows.CloneableOpenSupport findCloneableOpenSupport() { 386 return (JSFConfigEditorSupport) getDataObject().getCookie(JSFConfigEditorSupport.class); 387 } 388 } 389 } 390 | Popular Tags |