1 19 20 package org.netbeans.modules.diff.builtin.visualizer.editable; 21 22 import java.awt.event.*; 23 import java.awt.*; 24 import java.beans.PropertyChangeListener ; 25 import java.beans.PropertyChangeSupport ; 26 import java.beans.PropertyChangeEvent ; 27 import java.util.*; 28 import java.util.logging.Logger ; 29 import java.util.logging.Level ; 30 import java.io.*; 31 import java.lang.reflect.InvocationTargetException ; 32 import java.lang.reflect.Method ; 33 import javax.swing.*; 34 import javax.swing.plaf.basic.BasicSplitPaneUI ; 35 import javax.swing.plaf.basic.BasicSplitPaneDivider ; 36 import javax.swing.event.DocumentListener ; 37 import javax.swing.event.DocumentEvent ; 38 import javax.swing.event.AncestorListener ; 39 import javax.swing.event.AncestorEvent ; 40 import javax.swing.text.*; 41 import org.netbeans.api.editor.fold.FoldHierarchy; 42 import org.netbeans.api.editor.fold.FoldUtilities; 43 import org.netbeans.api.editor.fold.FoldHierarchyListener; 44 import org.netbeans.api.editor.fold.FoldHierarchyEvent; 45 import org.netbeans.modules.diff.NestableDiffView; 46 import org.netbeans.modules.diff.builtin.provider.BuiltInDiffProvider; 47 import org.netbeans.modules.diff.builtin.visualizer.GraphicalDiffVisualizer; 48 import org.netbeans.modules.diff.builtin.visualizer.SourceTranslatorAction; 49 50 import org.openide.util.Lookup; 51 import org.openide.util.RequestProcessor; 52 import org.openide.util.NbBundle; 53 import org.openide.ErrorManager; 54 import org.openide.awt.UndoRedo; 55 import org.openide.filesystems.FileObject; 56 import org.openide.text.CloneableEditorSupport; 57 import org.openide.cookies.SaveCookie; 58 import org.openide.cookies.EditorCookie; 59 import org.openide.loaders.DataObject; 60 import org.netbeans.api.diff.Difference; 61 import org.netbeans.api.diff.StreamSource; 62 import org.netbeans.api.diff.DiffView; 63 import org.netbeans.spi.diff.DiffProvider; 64 import org.netbeans.spi.diff.DiffVisualizer; 65 66 72 public class EditableDiffView implements DiffView, NestableDiffView, DocumentListener , AncestorListener , PropertyChangeListener { 73 74 private Color colorMissing = new Color(255, 160, 180); 76 private Color colorAdded = new Color(180, 255, 180); 77 private Color colorChanged = new Color(160, 200, 255); 78 private Color colorLines = Color.DARK_GRAY; 79 private Color COLOR_READONLY_BG = new Color(240,240,240); 80 81 private final Difference [] NO_DIFFERENCES = new Difference[0]; 82 83 86 private DiffContentPanel jEditorPane1; 87 88 91 private DiffContentPanel jEditorPane2; 92 93 private boolean secondSourceAvailable; 94 private boolean firstSourceAvailable; 95 96 private JViewport jViewport2; 97 98 final JLabel fileLabel1 = new JLabel(); 99 final JLabel fileLabel2 = new JLabel(); 100 final JPanel filePanel1 = new JPanel(); 101 final JPanel filePanel2 = new JPanel(); 102 final JSplitPane jSplitPane1 = new JSplitPane(); 103 104 private int diffSerial; 105 private Difference[] diffs = NO_DIFFERENCES; 106 107 private int currentDiffIndex = -1; 108 109 private int totalHeight = 0; 110 private int totalLines = 0; 111 112 private int horizontalScroll1ChangedValue = -1; 113 private int horizontalScroll2ChangedValue = -1; 114 115 private RequestProcessor.Task refreshDiffTask; 116 private DiffViewManager manager; 117 118 private boolean actionsEnabled; 119 private DiffSplitPaneUI spui; 120 121 124 private EditorCookie.Observable editableCookie; 125 private Document editableDocument; 126 private UndoRedo.Manager editorUndoRedo; 127 128 public EditableDiffView() { 129 } 130 131 public EditableDiffView(final StreamSource ss1, final StreamSource ss2) throws IOException { 132 refreshDiffTask = RequestProcessor.getDefault().create(new RefreshDiffTask()); 133 initColors(); 134 String title1 = ss1.getTitle(); 135 if (title1 == null) title1 = NbBundle.getMessage(EditableDiffView.class, "CTL_DiffPanel_NoTitle"); String title2 = ss2.getTitle(); 137 if (title2 == null) title2 = NbBundle.getMessage(EditableDiffView.class, "CTL_DiffPanel_NoTitle"); String mimeType1 = ss1.getMIMEType(); 139 String mimeType2 = ss2.getMIMEType(); 140 if (mimeType1 == null) mimeType1 = mimeType2; 141 if (mimeType2 == null) mimeType2 = mimeType1; 142 143 actionsEnabled = ss2.isEditable(); 144 145 jEditorPane1 = new DiffContentPanel(this, true); 146 jEditorPane2 = new DiffContentPanel(this, false); 147 148 initComponents (); 149 jSplitPane1.setName(org.openide.util.NbBundle.getMessage(EditableDiffView.class, "DiffComponent.title")); spui = new DiffSplitPaneUI(jSplitPane1); 151 jSplitPane1.setUI(spui); 152 jSplitPane1.setResizeWeight(0.5); 153 jSplitPane1.setDividerSize(32); 154 jSplitPane1.putClientProperty("PersistenceType", "Never"); jSplitPane1.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(EditableDiffView.class, "ACS_DiffPanelA11yName")); jSplitPane1.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(EditableDiffView.class, "ACS_DiffPanelA11yDesc")); jEditorPane1.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(EditableDiffView.class, "ACS_EditorPane1A11yName")); jEditorPane1.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(EditableDiffView.class, "ACS_EditorPane1A11yDescr")); jEditorPane2.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(EditableDiffView.class, "ACS_EditorPane2A11yName")); jEditorPane2.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(EditableDiffView.class, "ACS_EditorPane2A11yDescr")); 162 jSplitPane1.addAncestorListener(this); 163 164 setSourceTitle(fileLabel1, title1); 165 setSourceTitle(fileLabel2, title2); 166 167 final String f1 = mimeType1; 168 final String f2 = mimeType2; 169 try { 170 Runnable awtTask = new Runnable () { 171 public void run() { 172 jEditorPane1.getEditorPane().setEditorKit(CloneableEditorSupport.getEditorKit(f1)); 173 jEditorPane2.getEditorPane().setEditorKit(CloneableEditorSupport.getEditorKit(f2)); 174 175 try { 176 setSource1(ss1); 177 setSource2(ss2); 178 } catch (IOException ioex) { 179 org.openide.ErrorManager.getDefault().notify(ioex); 180 } 181 182 if (!secondSourceAvailable) { 183 jEditorPane2.getEditorPane().setText(NbBundle.getMessage(EditableDiffView.class, "CTL_DiffPanel_NoContent")); } 185 if (!firstSourceAvailable) { 186 jEditorPane1.getEditorPane().setText(NbBundle.getMessage(EditableDiffView.class, "CTL_DiffPanel_NoContent")); } 188 189 Color borderColor = UIManager.getColor("scrollpane_border"); if (borderColor == null) borderColor = UIManager.getColor("controlShadow"); 192 jEditorPane1.getScrollPane().setBorder(null); 193 jEditorPane2.getScrollPane().setBorder(null); 194 195 jEditorPane1.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, borderColor)); 196 jEditorPane2.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, borderColor)); 197 jSplitPane1.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, borderColor)); 198 } 199 }; 200 if (SwingUtilities.isEventDispatchThread()) { 201 awtTask.run(); 202 } else { 203 SwingUtilities.invokeAndWait(awtTask); 204 } 205 } catch (InterruptedException e) { 206 ErrorManager err = ErrorManager.getDefault(); 207 err.notify(e); 208 } catch (InvocationTargetException e) { 209 ErrorManager err = ErrorManager.getDefault(); 210 err.notify(e); 211 } 212 213 refreshDiffTask.run(); 214 215 manager = new DiffViewManager(this); 216 manager.init(); 217 } 218 219 222 public boolean isActionsEnabled() { 223 return actionsEnabled; 224 } 225 226 private void initColors() { 227 Lookup.Result<DiffVisualizer> dv = Lookup.getDefault().lookup(new Lookup.Template<DiffVisualizer>(DiffVisualizer.class)); 228 Collection c = dv.allInstances(); 229 for (Iterator i = c.iterator(); i.hasNext();) { 230 Object o = i.next(); 231 if (o instanceof GraphicalDiffVisualizer) { 232 GraphicalDiffVisualizer gdv = (GraphicalDiffVisualizer) o; 233 colorAdded = gdv.getColorAdded(); 234 colorChanged = gdv.getColorChanged(); 235 colorMissing = gdv.getColorMissing(); 236 } 237 } 238 } 239 240 public void ancestorAdded(AncestorEvent event) { 241 expandFolds(); 242 initGlobalSizes(); 243 addChangeListeners(); 244 refreshDiff(50); 245 246 if (editableCookie == null) return; 247 refreshEditableDocument(); 248 editableCookie.addPropertyChangeListener(this); 249 } 250 251 private void refreshEditableDocument() { 252 Document doc = null; 253 try { 254 doc = editableCookie.openDocument(); 255 } catch (IOException e) { 256 Logger.getLogger(EditableDiffView.class.getName()).log(Level.INFO, "Getting new Document from EditorCookie", e); return; 258 } 259 editableDocument.removeDocumentListener(this); 260 if (doc != editableDocument) { 261 editableDocument = doc; 262 jEditorPane2.getEditorPane().setDocument(editableDocument); 263 refreshDiff(20); 264 } 265 editableDocument.addDocumentListener(this); 266 } 267 268 public void ancestorRemoved(AncestorEvent event) { 269 if (editableCookie != null) { 270 editableDocument.removeDocumentListener(this); 271 saveModifiedDocument(); 272 editableCookie.removePropertyChangeListener(this); 273 if (editableCookie.getOpenedPanes() == null) { 274 editableCookie.close(); 275 } 276 } 277 } 278 279 private void saveModifiedDocument() { 280 DataObject dao = (DataObject) editableDocument.getProperty(Document.StreamDescriptionProperty); 281 if (dao != null) { 282 SaveCookie sc = dao.getCookie(SaveCookie.class); 283 if (sc != null) { 284 try { 285 sc.save(); 286 } catch (IOException e) { 287 Logger.getLogger(EditableDiffView.class.getName()).log(Level.INFO, "Error saving Diff document", e); } 289 } 290 } 291 } 292 293 public void ancestorMoved(AncestorEvent event) { 294 } 295 296 public void insertUpdate(DocumentEvent e) { 297 refreshDiff(50); 298 } 299 300 public void removeUpdate(DocumentEvent e) { 301 refreshDiff(50); 302 } 303 304 public void changedUpdate(DocumentEvent e) { 305 refreshDiff(50); 306 } 307 308 Color getColor(Difference ad) { 309 if (ad.getType() == Difference.ADD) return colorAdded; 310 if (ad.getType() == Difference.CHANGE) return colorChanged; 311 return colorMissing; 312 } 313 314 JComponent getMyDivider() { 315 return spui.divider.getDivider(); 316 } 317 318 DiffContentPanel getEditorPane1() { 319 return jEditorPane1; 320 } 321 322 DiffContentPanel getEditorPane2() { 323 return jEditorPane2; 324 } 325 326 public DiffViewManager getManager() { 327 return manager; 328 } 329 330 Difference[] getDifferences() { 331 return diffs; 332 } 333 334 339 void rollback(Difference diff) { 340 if (diff == null) { 341 try { 342 Document dest = getEditorPane2().getEditorPane().getDocument(); 343 Document src = getEditorPane1().getEditorPane().getDocument(); 344 dest.remove(0, dest.getLength()); 345 dest.insertString(0, src.getText(0, src.getLength()), null); 346 } catch (BadLocationException e) { 347 ErrorManager.getDefault().notify(e); 348 } 349 return; 350 } 351 try { 352 Document document = getEditorPane2().getEditorPane().getDocument(); 353 if (diff.getType() == Difference.ADD) { 354 int start = DiffViewManager.getRowStartFromLineOffset(document, diff.getSecondStart() - 1); 355 int end = DiffViewManager.getRowStartFromLineOffset(document, diff.getSecondEnd()); 356 document.remove(start, end - start); 357 } else if (diff.getType() == Difference.DELETE) { 358 int start = DiffViewManager.getRowStartFromLineOffset(document, diff.getSecondStart()); 359 document.insertString(start, diff.getFirstText(), null); 360 } else { 361 int start = DiffViewManager.getRowStartFromLineOffset(document, diff.getSecondStart() - 1); 362 int end = DiffViewManager.getRowStartFromLineOffset(document, diff.getSecondEnd()); 363 document.remove(start, end - start); 364 document.insertString(start, diff.getFirstText(), null); 365 } 366 } catch (BadLocationException e) { 367 ErrorManager.getDefault().notify(e); 368 } 369 } 370 371 class DiffSplitPaneUI extends BasicSplitPaneUI { 372 373 final DiffSplitPaneDivider divider; 374 375 public DiffSplitPaneUI(JSplitPane splitPane) { 376 this.splitPane = splitPane; 377 divider = new DiffSplitPaneDivider(this, EditableDiffView.this); 378 } 379 380 public BasicSplitPaneDivider createDefaultDivider() { 381 return divider; 382 } 383 } 384 385 public boolean requestFocusInWindow() { 386 return jEditorPane1.requestFocusInWindow(); 387 } 388 389 public JComponent getComponent() { 390 return jSplitPane1; 391 } 392 393 public int getDifferenceCount() { 394 return diffs.length; 395 } 396 397 public boolean canSetCurrentDifference() { 398 return true; 399 } 400 401 public void setCurrentDifference(int diffNo) throws UnsupportedOperationException { 402 if (diffNo < -1 || diffNo >= diffs.length) throw new IllegalArgumentException ("Illegal difference number: " + diffNo); if (diffNo == -1) { 404 } else { 405 currentDiffIndex = diffNo; 406 showCurrentLine(); 407 } 408 } 409 410 public int getCurrentDifference() throws UnsupportedOperationException { 411 int firstVisibleLine; 412 int lastVisibleLine; 413 int candidate = currentDiffIndex; 414 if (jViewport2 != null) { 415 int viewHeight = jViewport2.getViewSize().height; 416 java.awt.Point p1; 417 initGlobalSizes(); p1 = jViewport2.getViewPosition(); 419 int HALFLINE_CEILING = 2; float firstPct = ((float)p1.y / (float)viewHeight); 421 firstVisibleLine = (int) (firstPct * totalLines) + HALFLINE_CEILING; 422 float lastPct = ((float)(jViewport2.getHeight() + p1.y) / (float)viewHeight); 423 lastVisibleLine = (int) (lastPct * totalLines) - HALFLINE_CEILING; 424 425 for (int i = 0; i<diffs.length; i++) { 426 int startLine = diffs[i].getSecondStart(); 427 int endLine = diffs[i].getSecondEnd(); if (firstVisibleLine < startLine && startLine < lastVisibleLine 429 || firstVisibleLine < endLine && endLine < lastVisibleLine) { 430 if (i == currentDiffIndex) { 431 return currentDiffIndex; } 433 candidate = i; } 435 } 436 } 437 438 return candidate; 439 } 440 441 public JToolBar getToolBar() { 442 return null; 443 } 444 445 private void showCurrentLine() { 446 Difference diff = diffs[currentDiffIndex]; 447 448 int off1, off2; 449 initGlobalSizes(); try { 451 off1 = org.openide.text.NbDocument.findLineOffset((StyledDocument) jEditorPane1.getEditorPane().getDocument(), diff.getFirstStart() - 1); 452 off2 = org.openide.text.NbDocument.findLineOffset((StyledDocument) jEditorPane2.getEditorPane().getDocument(), diff.getSecondStart() - 1); 453 454 jEditorPane1.getEditorPane().setCaretPosition(off1); 455 jEditorPane2.getEditorPane().setCaretPosition(off2); 456 } catch (IndexOutOfBoundsException ex) { 457 ErrorManager.getDefault().notify(ex); 458 } 459 460 manager.scroll(); 462 } 463 464 466 private void initComponents() { 467 java.awt.GridBagConstraints gridBagConstraints; 468 469 jSplitPane1.setDividerSize(4); 470 filePanel1.setLayout(new java.awt.GridBagLayout ()); 471 472 gridBagConstraints = new java.awt.GridBagConstraints (); 473 gridBagConstraints.gridx = 0; 474 gridBagConstraints.gridy = 1; 475 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; 476 gridBagConstraints.weightx = 1.0; 477 gridBagConstraints.weighty = 1.0; 478 filePanel1.add(jEditorPane1, gridBagConstraints); 479 480 fileLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); 481 fileLabel1.setLabelFor(jEditorPane1); 482 gridBagConstraints = new java.awt.GridBagConstraints (); 483 gridBagConstraints.gridx = 0; 484 gridBagConstraints.gridy = 0; 485 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; 486 gridBagConstraints.weightx = 1.0; 487 gridBagConstraints.insets = new java.awt.Insets (4, 4, 4, 4); 488 filePanel1.add(fileLabel1, gridBagConstraints); 489 490 jSplitPane1.setLeftComponent(filePanel1); 491 492 filePanel2.setLayout(new java.awt.GridBagLayout ()); 493 494 gridBagConstraints = new java.awt.GridBagConstraints (); 495 gridBagConstraints.gridx = 0; 496 gridBagConstraints.gridy = 1; 497 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; 498 gridBagConstraints.weightx = 1.0; 499 gridBagConstraints.weighty = 1.0; 500 filePanel2.add(jEditorPane2, gridBagConstraints); 501 502 fileLabel2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); 503 fileLabel2.setLabelFor(jEditorPane2); 504 gridBagConstraints = new java.awt.GridBagConstraints (); 505 gridBagConstraints.gridx = 0; 506 gridBagConstraints.gridy = 0; 507 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; 508 gridBagConstraints.weightx = 1.0; 509 gridBagConstraints.insets = new java.awt.Insets (4, 4, 4, 4); 510 filePanel2.add(fileLabel2, gridBagConstraints); 511 512 jSplitPane1.setRightComponent(filePanel2); 513 } 514 515 private void expandFolds(JEditorPane pane) { 517 final FoldHierarchy fh = FoldHierarchy.get(pane); 518 FoldUtilities.expandAll(fh); 519 fh.addFoldHierarchyListener(new FoldHierarchyListener() { 520 public void foldHierarchyChanged(FoldHierarchyEvent evt) { 521 FoldUtilities.expandAll(fh); 522 } 523 }); 524 } 525 526 private void expandFolds() { 527 expandFolds(jEditorPane1.getEditorPane()); 528 expandFolds(jEditorPane2.getEditorPane()); 529 } 530 531 private void initGlobalSizes() { 532 StyledDocument doc1 = (StyledDocument) jEditorPane1.getEditorPane().getDocument(); 533 StyledDocument doc2 = (StyledDocument) jEditorPane2.getEditorPane().getDocument(); 534 int numLines1 = org.openide.text.NbDocument.findLineNumber(doc1, doc1.getEndPosition().getOffset()); 535 int numLines2 = org.openide.text.NbDocument.findLineNumber(doc2, doc2.getEndPosition().getOffset()); 536 537 int numLines = Math.max(numLines1, numLines2); 538 if (numLines < 1) numLines = 1; 539 this.totalLines = numLines; 540 int totHeight = jEditorPane1.getSize().height; 541 int value = jEditorPane2.getSize().height; 542 if (value > totHeight) totHeight = value; 543 this.totalHeight = totHeight; 544 } 545 546 548 public void joinScrollPane(final JScrollPane pane) { 549 jEditorPane1.getScrollPane().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); 550 jEditorPane1.getScrollPane().setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 551 jEditorPane2.getScrollPane().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); 552 jEditorPane2.getScrollPane().setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 553 jEditorPane1.getScrollPane().setWheelScrollingEnabled(false); 554 jEditorPane2.getScrollPane().setWheelScrollingEnabled(false); 555 jEditorPane1.getScrollPane().addMouseWheelListener(new MouseWheelListener() { 556 public void mouseWheelMoved(MouseWheelEvent e) { 557 pane.dispatchEvent(e); 558 } 559 }); 560 jEditorPane2.getScrollPane().addMouseWheelListener(new MouseWheelListener() { 561 public void mouseWheelMoved(MouseWheelEvent e) { 562 pane.dispatchEvent(e); 563 } 564 }); 565 jEditorPane1.getEditorPane().getCaret().setVisible(false); 566 jEditorPane2.getEditorPane().getCaret().setVisible(false); 567 568 KeyStroke[] keyStrokes = new KeyStroke[] { 570 KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), 571 KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), 572 573 KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), 574 KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), 575 576 KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0), 577 KeyStroke.getKeyStroke(KeyEvent.VK_HOME, InputEvent.CTRL_MASK), 578 579 KeyStroke.getKeyStroke(KeyEvent.VK_HOME, InputEvent.CTRL_MASK), 580 KeyStroke.getKeyStroke(KeyEvent.VK_HOME, InputEvent.CTRL_MASK), 581 582 KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), 583 KeyStroke.getKeyStroke(KeyEvent.VK_END, InputEvent.CTRL_MASK), 584 585 KeyStroke.getKeyStroke(KeyEvent.VK_END, InputEvent.CTRL_MASK), 586 KeyStroke.getKeyStroke(KeyEvent.VK_END, InputEvent.CTRL_MASK), 587 588 KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), 589 KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), 590 591 KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), 592 KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), 593 594 KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), 595 KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), 596 597 KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), 598 KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), 599 600 KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), 601 KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), 602 }; 603 604 for (int i = 0; i<keyStrokes.length; i+=2) { 605 KeyStroke stroke = keyStrokes[i]; 606 KeyStroke stroke2 = keyStrokes[i+1]; 607 Object pane1Key = jEditorPane1.getInputMap().get(stroke); 608 Object pane2Key = jEditorPane2.getInputMap().get(stroke); 609 Object scrollKey = pane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).get(stroke2); 610 if (scrollKey != null) { 611 final Action scrollAction = pane.getActionMap().get(scrollKey); 612 jEditorPane1.getActionMap().put(pane1Key, new SourceTranslatorAction(scrollAction, pane)); 613 jEditorPane2.getActionMap().put(pane2Key, new SourceTranslatorAction(scrollAction, pane)); 614 } else { 615 } 617 } 618 619 } 620 621 public int getInnerScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { 622 return jEditorPane1.getEditorPane().getScrollableUnitIncrement(visibleRect, orientation, direction); 623 } 624 625 public int getInnerScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { 626 return jEditorPane1.getEditorPane().getScrollableBlockIncrement(visibleRect, orientation, direction); 627 } 628 629 public int getInnerWidth() { 630 Dimension d1 = jEditorPane1.getScrollPane().getViewport().getView().getPreferredSize(); 631 Dimension d2 = jEditorPane2.getScrollPane().getViewport().getView().getPreferredSize(); 632 return Math.max(d1.width, d2.width) * 2; 633 } 634 635 public void setInnerWidth(int width) { 636 Dimension dim = jEditorPane1.getScrollPane().getViewport().getViewSize(); 637 dim.width = width/2; 638 jEditorPane1.getScrollPane().getViewport().setViewSize(dim); 639 640 dim = jEditorPane2.getScrollPane().getViewport().getViewSize(); 641 dim.width = width/2; 642 jEditorPane2.getScrollPane().getViewport().setViewSize(dim); 643 644 jSplitPane1.setDividerLocation(0.5); 645 } 646 647 public void setHorizontalPosition(int pos) { 648 pos /= 2; 649 650 Point p = jEditorPane1.getScrollPane().getViewport().getViewPosition(); 651 p.x = pos; 652 jEditorPane1.getScrollPane().getViewport().setViewPosition(p); 653 654 p = jEditorPane2.getScrollPane().getViewport().getViewPosition(); 655 p.x = pos; 656 jEditorPane2.getScrollPane().getViewport().setViewPosition(p); 657 } 658 659 660 public int getChangeY(int change) { 661 Difference diff = diffs[change]; 662 int line = diff.getFirstStart(); 663 int padding = 5; 664 if (line <= 5) { 665 padding = line/2; 666 } 667 initGlobalSizes(); 668 int ypos = (totalHeight*(line - padding - 1))/(totalLines + 1); 669 ypos += fileLabel1.getHeight(); 670 return ypos; 671 } 672 673 private void joinScrollBars() { 674 final JScrollBar scrollBarH1 = jEditorPane1.getScrollPane().getHorizontalScrollBar(); 675 final JScrollBar scrollBarH2 = jEditorPane2.getScrollPane().getHorizontalScrollBar(); 676 677 scrollBarH1.getModel().addChangeListener(new javax.swing.event.ChangeListener () { 678 public void stateChanged(javax.swing.event.ChangeEvent e) { 679 int value = scrollBarH1.getValue(); 680 if (value == horizontalScroll1ChangedValue) return; 681 int max1 = scrollBarH1.getMaximum(); 682 int max2 = scrollBarH2.getMaximum(); 683 int ext1 = scrollBarH1.getModel().getExtent(); 684 int ext2 = scrollBarH2.getModel().getExtent(); 685 if (max1 == ext1) horizontalScroll2ChangedValue = 0; 686 else horizontalScroll2ChangedValue = (value*(max2 - ext2))/(max1 - ext1); 687 horizontalScroll1ChangedValue = -1; 688 scrollBarH2.setValue(horizontalScroll2ChangedValue); 689 } 690 }); 691 scrollBarH2.getModel().addChangeListener(new javax.swing.event.ChangeListener () { 692 public void stateChanged(javax.swing.event.ChangeEvent e) { 693 int value = scrollBarH2.getValue(); 694 if (value == horizontalScroll2ChangedValue) return; 695 int max1 = scrollBarH1.getMaximum(); 696 int max2 = scrollBarH2.getMaximum(); 697 int ext1 = scrollBarH1.getModel().getExtent(); 698 int ext2 = scrollBarH2.getModel().getExtent(); 699 if (max2 == ext2) horizontalScroll1ChangedValue = 0; 700 else horizontalScroll1ChangedValue = (value*(max1 - ext1))/(max2 - ext2); 701 horizontalScroll2ChangedValue = -1; 702 scrollBarH1.setValue(horizontalScroll1ChangedValue); 703 } 704 }); 705 jSplitPane1.setDividerLocation(0.5); 706 } 707 708 private void customizeEditor(JEditorPane editor) { 709 StyledDocument doc; 710 Document document = editor.getDocument(); 711 try { 712 doc = (StyledDocument) editor.getDocument(); 713 } catch(ClassCastException e) { 714 doc = new DefaultStyledDocument(); 715 try { 716 doc.insertString(0, document.getText(0, document.getLength()), null); 717 } catch (BadLocationException ble) { 718 } 720 editor.setDocument(doc); 721 } 722 } 723 724 private void addChangeListeners() { 725 jEditorPane1.getEditorPane().addPropertyChangeListener("font", new java.beans.PropertyChangeListener () { public void propertyChange(java.beans.PropertyChangeEvent evt) { 727 javax.swing.SwingUtilities.invokeLater(new Runnable () { 728 public void run() { 729 diffSerial++; initGlobalSizes(); 731 jEditorPane1.onUISettingsChanged(); 732 getComponent().revalidate(); 733 getComponent().repaint(); 734 } 735 }); 736 } 737 }); 738 jEditorPane2.getEditorPane().addPropertyChangeListener("font", new java.beans.PropertyChangeListener () { public void propertyChange(java.beans.PropertyChangeEvent evt) { 740 javax.swing.SwingUtilities.invokeLater(new Runnable () { 741 public void run() { 742 diffSerial++; initGlobalSizes(); 744 jEditorPane2.onUISettingsChanged(); 745 getComponent().revalidate(); 746 getComponent().repaint(); 747 } 748 }); 749 } 750 }); 751 } 752 753 private void setSource1(StreamSource ss) throws IOException { 754 firstSourceAvailable = false; 755 EditorKit kit = jEditorPane1.getEditorPane().getEditorKit(); 756 if (kit == null) throw new IOException("Missing Editor Kit"); 758 Document sdoc = getSourceDocument(ss); 759 Document doc = sdoc != null ? sdoc : kit.createDefaultDocument(); 760 if (!(doc instanceof StyledDocument)) { 761 doc = new DefaultStyledDocument(new StyleContext()); 762 kit = new StyledEditorKit(); 763 jEditorPane1.getEditorPane().setEditorKit(kit); 764 } 765 if (sdoc == null) { 766 Reader r = ss.createReader(); 767 if (r != null) { 768 firstSourceAvailable = true; 769 try { 770 kit.read(r, doc, 0); 771 } catch (javax.swing.text.BadLocationException e) { 772 throw new IOException("Can not locate the beginning of the document."); } finally { 774 r.close(); 775 } 776 } 777 } else { 778 firstSourceAvailable = true; 779 } 780 jEditorPane1.initActions(); 781 jEditorPane1.getEditorPane().setDocument(doc); 782 customizeEditor(jEditorPane1.getEditorPane()); 783 jViewport2 = jEditorPane2.getScrollPane().getViewport(); 784 } 785 786 private Document getSourceDocument(StreamSource ss) { 787 Document sdoc = null; 788 FileObject fo = ss.getLookup().lookup(FileObject.class); 789 if (fo != null) { 790 try { 791 DataObject dao = DataObject.find(fo); 792 EditorCookie ec = dao.getCookie(EditorCookie.class); 793 if (ec != null) { 794 sdoc = ec.openDocument(); 795 } 796 } catch (Exception e) { 797 } 799 } else { 800 sdoc = ss.getLookup().lookup(Document.class); 801 } 802 return sdoc; 803 } 804 805 private void setSource2(StreamSource ss) throws IOException { 806 secondSourceAvailable = false; 807 EditorKit kit = jEditorPane2.getEditorPane().getEditorKit(); 808 if (kit == null) throw new IOException("Missing Editor Kit"); 810 Document sdoc = getSourceDocument(ss); 811 if (sdoc != null && ss.isEditable()) { 812 DataObject dao = (DataObject) sdoc.getProperty(Document.StreamDescriptionProperty); 813 if (dao != null) { 814 EditorCookie cookie = dao.getCookie(EditorCookie.class); 815 if (cookie instanceof EditorCookie.Observable) { 816 editableCookie = (EditorCookie.Observable) cookie; 817 editableDocument = sdoc; 818 editorUndoRedo = getUndoRedo(cookie); 819 } 820 } 821 } 822 Document doc = sdoc != null ? sdoc : kit.createDefaultDocument(); 823 if (!(doc instanceof StyledDocument)) { 824 doc = new DefaultStyledDocument(new StyleContext()); 825 kit = new StyledEditorKit(); 826 jEditorPane2.getEditorPane().setEditorKit(kit); 827 } 828 if (sdoc == null) { 829 Reader r = ss.createReader(); 830 if (r != null) { 831 secondSourceAvailable = true; 832 try { 833 kit.read(r, doc, 0); 834 } catch (javax.swing.text.BadLocationException e) { 835 throw new IOException("Can not locate the beginning of the document."); } finally { 837 r.close(); 838 } 839 } 840 } else { 841 secondSourceAvailable = true; 842 } 843 jEditorPane2.initActions(); 844 jSplitPane1.putClientProperty(UndoRedo.class, editorUndoRedo); 845 jEditorPane2.getEditorPane().setDocument(doc); 846 jEditorPane2.getEditorPane().setEditable(editableCookie != null); 847 if (jEditorPane2.getEditorPane().isEditable()) { 848 jEditorPane1.getEditorPane().setBackground(COLOR_READONLY_BG); 849 } 850 851 customizeEditor(jEditorPane2.getEditorPane()); 852 joinScrollBars(); 853 } 854 855 private UndoRedo.Manager getUndoRedo(EditorCookie cookie) { 856 try { 858 Method method = CloneableEditorSupport.class.getDeclaredMethod("getUndoRedo"); method.setAccessible(true); 860 return (UndoRedo.Manager) method.invoke(cookie); 861 } catch (Exception e) { 862 e.printStackTrace(); 863 } 864 return null; 865 } 866 867 public void propertyChange(final PropertyChangeEvent evt) { 868 if (EditorCookie.Observable.PROP_DOCUMENT.equals(evt.getPropertyName())) { 869 SwingUtilities.invokeLater(new Runnable () { 870 public void run() { 871 refreshEditableDocument(); 872 } 873 }); 874 } 875 } 876 877 public void setSourceTitle(JLabel label, String title) { 878 label.setText(title); 879 label.setMinimumSize(new Dimension(3, label.getMinimumSize().height)); 881 } 882 883 public void setDocument1(Document doc) { 884 if (doc != null) { 885 jEditorPane1.getEditorPane().setDocument(doc); 886 } 887 } 888 889 public void setDocument2(Document doc) { 890 if (doc != null) { 891 jEditorPane2.getEditorPane().setDocument(doc); 892 } 893 } 894 895 private void refreshDiff(int delayMillis) { 896 refreshDiffTask.schedule(delayMillis); 897 } 898 899 public class RefreshDiffTask implements Runnable { 900 901 public void run() { 902 synchronized(EditableDiffView.this) { 903 computeDiff(); 904 SwingUtilities.invokeLater(new Runnable () { 905 public void run() { 906 jEditorPane1.setCurrentDiff(diffs); 907 jEditorPane2.setCurrentDiff(diffs); 908 jSplitPane1.repaint(); 909 } 910 }); 911 } 912 } 913 914 private boolean equals(Difference[] a, Difference[] b) { 915 if (a == null || b == null || a.length != b.length) return false; 916 for (int i = 0; i < a.length; i++) { 917 Difference ad = a[i]; 918 Difference bd = b[i]; 919 if (ad.getType() != bd.getType() || 920 ad.getFirstStart() != bd.getFirstStart() || 921 ad.getSecondStart() != bd.getSecondStart() || 922 ad.getFirstEnd() != bd.getFirstEnd() || 923 ad.getSecondEnd() != bd.getSecondEnd()) return false; 924 } 925 return true; 926 } 927 928 private void computeDiff() { 929 if (!secondSourceAvailable || !firstSourceAvailable) { 930 diffs = NO_DIFFERENCES; 931 return; 932 } 933 934 Reader first = null; 935 Reader second = null; 936 try { 937 first = new StringReader(jEditorPane1.getEditorPane().getDocument().getText(0, jEditorPane1.getEditorPane().getDocument().getLength())); 938 second = new StringReader(jEditorPane2.getEditorPane().getDocument().getText(0, jEditorPane2.getEditorPane().getDocument().getLength())); 939 } catch (BadLocationException e) { 940 ErrorManager.getDefault().notify(e); 941 } 942 943 DiffProvider diff = Lookup.getDefault().lookup(DiffProvider.class); 944 if (diff == null) { 945 diffs = NO_DIFFERENCES; 946 return; 947 } 948 boolean isTrim = false; 949 if (diff instanceof BuiltInDiffProvider) { 950 isTrim = ((BuiltInDiffProvider) diff).isTrimLines(); 951 ((BuiltInDiffProvider) diff).setTrimLines(false); 952 } 953 try { 954 diffs = diff.computeDiff(first, second); 955 diffSerial++; 956 } catch (IOException e) { 957 diffs = NO_DIFFERENCES; 958 } 959 if (diff instanceof BuiltInDiffProvider) { 960 ((BuiltInDiffProvider) diff).setTrimLines(isTrim); 961 } 962 } 963 } 964 965 int getDiffSerial() { 966 return diffSerial; 967 } 968 969 static Difference getFirstDifference(Difference [] diff, int line) { 970 if (line < 0) return null; 971 for (int i = 0; i < diff.length; i++) { 972 Difference difference = diff[i]; 973 if (line < difference.getFirstStart()) return null; 974 if (difference.getType() == Difference.ADD && line == difference.getFirstStart()) return difference; 975 if (line <= difference.getFirstEnd()) return difference; 976 } 977 return null; 978 } 979 980 static Difference getSecondDifference(Difference [] diff, int line) { 981 if (line < 0) return null; 982 for (int i = 0; i < diff.length; i++) { 983 Difference difference = diff[i]; 984 if (line < difference.getSecondStart()) return null; 985 if (difference.getType() == Difference.DELETE && line == difference.getSecondStart()) return difference; 986 if (line <= difference.getSecondEnd()) return difference; 987 } 988 return null; 989 } 990 991 Color getColorLines() { 992 return colorLines; 993 } 994 995 private PropertyChangeSupport support = new PropertyChangeSupport (this); 996 997 public void addPropertyChangeListener(PropertyChangeListener l) { 998 support.addPropertyChangeListener(l); 999 } 1000 1001 public void removePropertyChangeListener(PropertyChangeListener l) { 1002 support.removePropertyChangeListener(l); 1003 } 1004} 1005 | Popular Tags |