1 19 20 package org.netbeans.modules.xml.schema.core; 21 22 import java.awt.EventQueue ; 23 import java.io.ByteArrayOutputStream ; 24 import java.io.CharConversionException ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.InputStreamReader ; 28 import java.io.OutputStream ; 29 import java.io.OutputStreamWriter ; 30 import java.io.Reader ; 31 import java.io.Serializable ; 32 import java.io.UnsupportedEncodingException ; 33 import java.io.Writer ; 34 import java.util.ArrayList ; 35 import java.util.List ; 36 import java.util.Set ; 37 import javax.swing.text.AbstractDocument ; 38 import javax.swing.text.BadLocationException ; 39 import javax.swing.text.Document ; 40 import javax.swing.text.EditorKit ; 41 import javax.swing.text.StyledDocument ; 42 import org.netbeans.core.api.multiview.MultiViewHandler; 43 import org.netbeans.core.api.multiview.MultiViews; 44 import org.netbeans.core.spi.multiview.CloseOperationHandler; 45 import org.netbeans.core.spi.multiview.CloseOperationState; 46 import org.netbeans.modules.xml.axi.AXIModel; 47 import org.netbeans.modules.xml.axi.AXIModelFactory; 48 import org.netbeans.modules.xml.retriever.catalog.Utilities; 49 import org.netbeans.modules.xml.xam.ModelSource; 50 import org.netbeans.modules.xml.schema.core.multiview.SchemaMultiViewSupport; 51 import org.netbeans.modules.xml.schema.model.SchemaModel; 52 import org.netbeans.modules.xml.schema.model.SchemaModelFactory; 53 import org.netbeans.modules.xml.schema.ui.basic.SchemaModelCookie; 54 import org.netbeans.modules.xml.xam.ui.undo.QuietUndoManager; 55 import org.openide.DialogDisplayer; 56 import org.openide.ErrorManager; 57 import org.openide.NotifyDescriptor; 58 import org.openide.awt.UndoRedo; 59 import org.openide.cookies.CloseCookie; 60 import org.openide.cookies.EditCookie; 61 import org.openide.cookies.EditorCookie; 62 import org.openide.cookies.LineCookie; 63 import org.openide.cookies.OpenCookie; 64 import org.openide.cookies.PrintCookie; 65 import org.openide.filesystems.FileLock; 66 import org.openide.filesystems.FileObject; 67 import org.openide.loaders.DataObject; 68 import org.openide.text.CloneableEditor; 69 import org.openide.text.CloneableEditorSupport; 70 import org.openide.text.CloneableEditorSupport.Pane; 71 import org.openide.text.DataEditorSupport; 72 import org.openide.text.NbDocument; 73 import org.openide.util.NbBundle; 74 import org.openide.util.Task; 75 import org.openide.util.TaskListener; 76 import org.openide.windows.Mode; 77 import org.openide.windows.TopComponent; 78 import org.openide.windows.WindowManager; 79 80 87 public class SchemaEditorSupport extends DataEditorSupport 88 implements SchemaModelCookie, OpenCookie, EditCookie, 89 EditorCookie.Observable, LineCookie, CloseCookie, PrintCookie { 90 91 private transient Task prepareTask2; 92 94 private transient boolean ignoreUpdateTitles; 95 96 101 public SchemaEditorSupport(SchemaDataObject dobj) { 102 super(dobj, new SchemaEditorEnv(dobj)); 103 setMIMEType(SchemaDataLoader.MIME_TYPE); 104 } 105 106 110 public SchemaEditorEnv getEnv() { 111 return (SchemaEditorEnv)env; 112 } 113 114 protected Pane createPane() { 115 TopComponent tc = SchemaMultiViewSupport.createMultiView( 116 (SchemaDataObject) getDataObject()); 117 121 Mode editorMode = WindowManager.getDefault().findMode( 122 SchemaEditorSupport.EDITOR_MODE); 123 if (editorMode != null) { 124 editorMode.dockInto(tc); 125 } 126 127 return (Pane) tc; 128 } 129 130 public void initializeCloneableEditor(CloneableEditor editor) { 132 super.initializeCloneableEditor(editor); 133 EventQueue.invokeLater(new Runnable () { 136 public void run() { 137 updateTitles(); 139 } 140 }); 141 } 142 143 150 public void ignoreUpdateTitles(boolean ignore) { 151 ignoreUpdateTitles = ignore; 152 } 158 159 protected void updateTitles() { 160 if (ignoreUpdateTitles) { 164 return; 165 } 166 167 super.updateTitles(); 169 170 EventQueue.invokeLater(new Runnable () { 172 public void run() { 173 List <TopComponent> associatedTCs = new ArrayList <TopComponent>(); 180 DataObject targetDO = getDataObject(); 181 TopComponent activeTC = TopComponent.getRegistry().getActivated(); 182 if (activeTC != null && targetDO == (DataObject) activeTC.getLookup().lookup( 183 DataObject.class)) { 184 associatedTCs.add(activeTC); 185 } 186 Set openTCs = TopComponent.getRegistry().getOpened(); 187 for (Object tc : openTCs) { 188 TopComponent tcc = (TopComponent) tc; 189 if (targetDO == (DataObject) tcc.getLookup().lookup( 190 DataObject.class)) { 191 associatedTCs.add(tcc); 192 } 193 } 194 for (TopComponent tc : associatedTCs) { 195 MultiViewHandler mvh = MultiViews.findMultiViewHandler(tc); 198 if (mvh != null) { 199 tc.setHtmlDisplayName(messageHtmlName()); 200 String name = messageName(); 201 tc.setDisplayName(name); 202 tc.setName(name); 203 tc.setToolTipText(messageToolTip()); 204 } 205 } 206 } 207 }); 208 } 209 210 @Override  211 protected UndoRedo.Manager createUndoRedoManager() { 212 return new QuietUndoManager(super.createUndoRedoManager()); 215 } 218 219 224 public QuietUndoManager getUndoManager() { 225 return (QuietUndoManager) getUndoRedo(); 226 } 227 228 public SchemaModel getModel() throws IOException { 229 SchemaDataObject dobj = getEnv().getSchemaDataObject(); 230 FileObject fobj = dobj.getPrimaryFile(); 231 ModelSource modelSource = Utilities.getModelSource(fobj, true); 232 boolean validModelSource = modelSource != null && 233 modelSource.getLookup().lookup(Document .class) != null; 234 if (!validModelSource) { 235 throw new IOException ( 236 NbBundle.getMessage(SchemaEditorSupport.class, 237 "MSG_UnableToCreateModel")); 238 } 239 return validModelSource ? SchemaModelFactory.getDefault().getModel(modelSource) : null; 240 } 241 242 249 public void addUndoManagerToDocument() { 250 QuietUndoManager undo = getUndoManager(); 254 StyledDocument doc = getDocument(); 255 synchronized (undo) { 256 try { 257 SchemaModel model = getModel(); 258 if (model != null) { 259 model.removeUndoableEditListener(undo); 260 } 261 undo.setModel(null); 263 AXIModel aModel = AXIModelFactory.getDefault().getModel(model); 264 undo.removeWrapperModel(aModel); 265 } catch (IOException ioe) { 266 } 269 if (doc != null) { 271 doc.removeUndoableEditListener(undo); 273 doc.addUndoableEditListener(undo); 274 undo.beginCompound(); 279 } 280 } 281 } 282 283 290 public void removeUndoManagerFromDocument() { 291 QuietUndoManager undo = getUndoManager(); 293 StyledDocument doc = getDocument(); 294 synchronized (undo) { 295 if (doc != null) { 297 doc.removeUndoableEditListener(undo); 298 undo.endCompound(); 299 } 300 addUndoManagerToModel(undo); 303 } 304 } 305 306 314 private void addUndoManagerToModel(QuietUndoManager undo) { 315 try { 317 SchemaModel model = getModel(); 318 if (model != null) { 319 model.removeUndoableEditListener(undo); 321 model.addUndoableEditListener(undo); 322 undo.setModel(model); 326 } 327 } catch (IOException ioe) { 328 } 330 } 331 332 340 private void removeUndoManagerFromModel(QuietUndoManager undo) { 341 try { 343 SchemaModel model = getModel(); 344 if (model != null) { 345 model.removeUndoableEditListener(undo); 346 undo.setModel(null); 347 } 348 } catch (IOException ioe) { 349 } 351 } 352 353 361 public boolean suspendUndoRedo() { 362 QuietUndoManager undo = getUndoManager(); 363 boolean compound; 364 synchronized (undo) { 365 compound = undo.isCompound(); 366 if (compound) { 367 removeUndoManagerFromDocument(); 368 } 369 removeUndoManagerFromModel(undo); 370 } 371 return compound; 372 } 373 374 381 public void resumeUndoRedo(boolean value) { 382 if (value) { 383 addUndoManagerToDocument(); 384 } else { 385 QuietUndoManager undo = getUndoManager(); 386 synchronized (undo) { 387 addUndoManagerToModel(undo); 388 } 389 } 390 } 391 392 protected void loadFromStreamToKit(StyledDocument doc, InputStream in, 393 EditorKit kit) throws IOException , BadLocationException { 394 String enc = EncodingHelper.detectEncoding(in); 396 if (enc == null) { 397 enc = "UTF8"; } 399 try { 400 Reader reader = new InputStreamReader (in, enc); 401 kit.read(reader, doc, 0); 402 } catch (CharConversionException cce) { 403 } catch (UnsupportedEncodingException uee) { 404 } 405 } 406 407 protected void saveFromKitToStream(StyledDocument doc, EditorKit kit, 408 OutputStream out) throws IOException , BadLocationException { 409 String enc = EncodingHelper.detectEncoding(doc); 411 if (enc == null) { 412 enc = "UTF8"; } 414 try { 415 new OutputStreamWriter (new ByteArrayOutputStream (1), enc); 417 Writer writer = new OutputStreamWriter (out, enc); 419 kit.write(writer, doc, 0, doc.getLength()); 420 } catch (UnsupportedEncodingException uee) { 421 IOException ioex = new IOException ("Unsupported encoding " + enc); ErrorManager.getDefault().annotate(ioex, 424 NbBundle.getMessage(SchemaEditorSupport.class, 425 "MSG_SchemaEditorSupport_Unsupported_Encoding", enc)); 426 throw ioex; 427 } 428 } 429 430 436 public boolean silentClose() { 437 return super.close(false); 438 } 439 440 public void saveDocument() throws IOException { 441 final StyledDocument doc = getDocument(); 442 String enc = EncodingHelper.detectEncoding(doc); 445 if (enc == null) { 446 enc = "UTF8"; } 448 try { 449 new OutputStreamWriter (new ByteArrayOutputStream (1), enc); 451 if (!checkCharsetConversion(Convertors.java2iana(enc))){ 452 return; 453 } 454 super.saveDocument(); 455 getDataObject().setModified(false); 456 457 } catch (UnsupportedEncodingException uee) { 458 NotifyDescriptor descriptor = new NotifyDescriptor.Confirmation( 459 java.text.MessageFormat.format( 460 NbBundle.getMessage(SchemaEditorSupport.class, 461 "MSG_SchemaEditorSupport_Use_UTF8"), 462 new Object [] {enc})); 463 Object res = DialogDisplayer.getDefault().notify(descriptor); 464 465 if (res.equals(NotifyDescriptor.YES_OPTION)) { 466 try { 468 final int MAX_PROLOG = 1000; 469 int maxPrologLen = Math.min(MAX_PROLOG, doc.getLength()); 470 final char prolog[] = doc.getText(0, maxPrologLen).toCharArray(); 471 int prologLen = 0; 472 if (prolog[0] == '<' && prolog[1] == '?' && prolog[2] == 'x') { 473 for (int i = 3; i < maxPrologLen; i++) { 474 if (prolog[i] == '?' && prolog[i + 1] == '>') { 475 prologLen = i + 1; 476 break; 477 } 478 } 479 } 480 481 final int passPrologLen = prologLen; 482 Runnable edit = new Runnable () { 483 public void run() { 484 try { 485 doc.remove(0, passPrologLen + 1); 486 doc.insertString(0, "<?xml version='1.0' encoding='UTF-8' ?>\n<!-- was: " + 487 new String (prolog, 0, passPrologLen + 1) + " -->", null); } catch (BadLocationException ble) { 489 if (System.getProperty("netbeans.debug.exceptions") != null) ble.printStackTrace(); 491 } 492 } 493 }; 494 NbDocument.runAtomic(doc, edit); 495 496 super.saveDocument(); 497 getDataObject().setModified(false); 498 499 } catch (BadLocationException lex) { 500 ErrorManager.getDefault().notify(lex); 501 } 502 } 503 } 504 } 505 506 513 private boolean checkCharsetConversion(String encoding) { 514 boolean value = true; 515 try { 516 java.nio.charset.CharsetEncoder coder = 517 java.nio.charset.Charset.forName(encoding).newEncoder(); 518 if (!coder.canEncode(getDocument().getText(0, 519 getDocument().getLength()))){ 520 Object [] margs = new Object [] { 521 getDataObject().getPrimaryFile().getNameExt(), 522 encoding 523 }; 524 String msg = NbBundle.getMessage(SchemaEditorSupport.class, 525 "MSG_SchemaEditorSupport_BadCharConversion", margs); 526 NotifyDescriptor nd = new NotifyDescriptor.Confirmation(msg, 527 NotifyDescriptor.YES_NO_OPTION, 528 NotifyDescriptor.WARNING_MESSAGE); 529 nd.setValue(NotifyDescriptor.NO_OPTION); 530 DialogDisplayer.getDefault().notify(nd); 531 if (nd.getValue() != NotifyDescriptor.YES_OPTION) { 532 value = false; 533 } 534 } 535 } catch (BadLocationException ble) { 536 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ble); 537 } 538 return value; 539 } 540 541 544 public void syncModel() { 545 try { 546 SchemaModel model = getModel(); 547 if (model != null) { 548 model.sync(); 549 } 550 } catch (IOException ioe) { 551 } 553 } 554 555 public Task prepareDocument() { 556 Task task = super.prepareDocument(); 557 if (task != prepareTask2) { 559 prepareTask2 = task; 560 task.addTaskListener(new TaskListener() { 561 public void taskFinished(Task task) { 562 QuietUndoManager undo = getUndoManager(); 563 StyledDocument doc = getDocument(); 564 synchronized (undo) { 565 undo.setDocument((AbstractDocument ) doc); 567 if (!undo.isCompound()) { 568 doc.removeUndoableEditListener(undo); 572 addUndoManagerToModel(undo); 574 } 575 } 576 prepareTask2 = null; 577 } 578 }); 579 } 580 return task; 581 } 582 583 public Task reloadDocument() { 584 Task task = super.reloadDocument(); 585 task.addTaskListener(new TaskListener() { 586 public void taskFinished(Task task) { 587 EventQueue.invokeLater(new Runnable () { 588 public void run() { 589 QuietUndoManager undo = getUndoManager(); 590 StyledDocument doc = getDocument(); 591 synchronized (undo) { 594 if (!undo.isCompound()) { 595 doc.removeUndoableEditListener(undo); 596 } 597 } 598 } 599 }); 600 } 601 }); 602 return task; 603 } 604 605 protected void notifyClosed() { 606 QuietUndoManager undo = getUndoManager(); 608 StyledDocument doc = getDocument(); 609 synchronized (undo) { 610 if (doc != null) { 612 doc.removeUndoableEditListener(undo); 613 undo.endCompound(); 614 undo.setDocument(null); 615 } 616 try { 617 SchemaModel model = getModel(); 618 if (model != null) { 619 model.removeUndoableEditListener(undo); 620 AXIModel aModel = AXIModelFactory.getDefault().getModel(model); 621 undo.removeWrapperModel(aModel); 622 } 623 undo.setModel(null); 625 } catch (IOException ioe) { 626 } 629 } 630 631 super.notifyClosed(); 632 } 633 634 639 protected static class SchemaEditorEnv extends DataEditorSupport.Env { 640 641 static final long serialVersionUID =1099957785497677206L; 642 643 public SchemaEditorEnv(SchemaDataObject obj) { 644 super(obj); 645 } 646 647 public CloneableEditorSupport findTextEditorSupport() { 648 return getSchemaDataObject().getSchemaEditorSupport(); 649 } 650 651 public SchemaDataObject getSchemaDataObject(){ 652 return (SchemaDataObject) getDataObject(); 653 } 654 655 protected FileObject getFile() { 656 return getDataObject().getPrimaryFile(); 657 } 658 659 protected FileLock takeLock() throws IOException { 660 return getDataObject().getPrimaryFile().lock(); 661 } 662 } 663 664 670 public static class CloseHandler implements CloseOperationHandler, Serializable { 671 private static final long serialVersionUID = -3838395157610633251L; 672 private DataObject dataObject; 673 674 private CloseHandler() { 675 super(); 676 } 677 678 public CloseHandler(DataObject schemaDO) { 679 dataObject = schemaDO; 680 } 681 682 private SchemaEditorSupport getSchemaEditorSupport() { 683 return dataObject == null ? null : 684 (SchemaEditorSupport) dataObject.getCookie( 685 SchemaEditorSupport.class); 686 } 687 688 public boolean resolveCloseOperation(CloseOperationState[] elements) { 689 SchemaEditorSupport schemaEditor = getSchemaEditorSupport(); 690 boolean canClose = schemaEditor != null ? schemaEditor.canClose() : true; 691 if (canClose) { 697 dataObject.setModified(false); 698 } 699 return canClose; 700 } 701 } 702 } 703 | Popular Tags |