1 19 20 package org.netbeans.modules.form; 21 22 import java.awt.Component ; 23 import java.awt.Container ; 24 import java.awt.Dimension ; 25 import java.awt.LayoutManager2 ; 26 import java.awt.event.ActionEvent ; 27 import java.awt.event.ActionListener ; 28 import java.lang.reflect.Modifier ; 29 import java.util.HashMap ; 30 import java.util.Iterator ; 31 import java.util.LinkedList ; 32 import java.util.List ; 33 import java.util.ListIterator ; 34 import java.util.Map ; 35 import javax.swing.DefaultComboBoxModel ; 36 import javax.swing.JComboBox ; 37 import javax.swing.JPanel ; 38 import javax.swing.event.DocumentEvent ; 39 import javax.swing.event.DocumentListener ; 40 import javax.swing.text.BadLocationException ; 41 import javax.swing.text.Document ; 42 import javax.swing.text.Element ; 43 import javax.swing.text.JTextComponent ; 44 import javax.swing.text.Position ; 45 import javax.swing.text.StyledDocument ; 46 47 import org.openide.ErrorManager; 48 import org.openide.text.NbDocument; 49 import org.openide.util.NbBundle; 50 51 import static org.netbeans.modules.form.CustomCodeData.*; 52 53 58 59 class CustomCodeView extends javax.swing.JPanel { 60 61 private CustomCodeData codeData; 62 private int lastLocalModifiers = -1; 63 private int lastFieldModifiers = -1; 64 65 private boolean changed; 66 67 interface Listener { 68 void componentExchanged(String compName); 69 void renameInvoked(); 70 void declarationChanged(); 71 } 72 73 private Listener controller; 74 75 private DocumentL docListener; 76 77 private boolean ignoreComboAction; 79 80 private static class EditBlockInfo { 81 Position position; 82 List <EditableLine> lines; 83 } 84 85 private static class GuardBlockInfo { 86 Position position; 87 String customizedCode; 88 boolean customized; 89 } 90 91 private Map <CodeCategory, EditBlockInfo[]> editBlockInfos; 92 private Map <CodeCategory, GuardBlockInfo[]> guardBlockInfos; 93 94 private Object documentContext; 95 96 98 CustomCodeView(Listener controller, Object documentContext) { 99 this.controller = controller; 100 this.documentContext = documentContext; 101 102 initComponents(); 103 104 variableCombo.setModel(new DefaultComboBoxModel (variableStrings)); 105 accessCombo.setModel(new DefaultComboBoxModel (accessStrings)); 106 107 Map <Component , Position > positions = new HashMap (); 110 initGutter = new JPanel (); 111 initGutter.setLayout(new GutterLayout(initCodeEditor, positions)); 112 declareGutter = new JPanel (); 113 declareGutter.setLayout(new GutterLayout(declareCodeEditor, positions)); 114 jScrollPane1.setRowHeaderView(initGutter); 115 jScrollPane2.setRowHeaderView(declareGutter); 116 } 119 120 public void addNotify() { 121 super.addNotify(); 122 initCodeEditor.requestFocusInWindow(); 123 } 124 125 boolean isChanged() { 126 return changed; 127 } 128 129 void setComponentNames(String [] compNames) { 130 componentCombo.setModel(new DefaultComboBoxModel (compNames)); 131 } 132 133 void setCodeData(String componentName, CustomCodeData codeData) { 134 if (this.codeData != null) { initCodeEditor.getDocument().removeDocumentListener(docListener); 136 declareCodeEditor.getDocument().removeDocumentListener(docListener); 137 initCodeEditor.setContentType("text/plain"); declareCodeEditor.setContentType("text/plain"); 141 initGutter.removeAll(); 142 declareGutter.removeAll(); 143 144 revalidate(); 145 repaint(); 146 } 147 148 if (editBlockInfos != null) { 149 editBlockInfos.clear(); 150 guardBlockInfos.clear(); 151 } 152 else { 153 editBlockInfos = new HashMap (); 154 guardBlockInfos = new HashMap (); 155 } 156 157 initCodeEditor.setContentType("text/x-java"); declareCodeEditor.setContentType("text/x-java"); 160 this.codeData = codeData; 161 selectInComboBox(componentCombo, componentName); 162 163 buildCodeView(CodeCategory.CREATE_AND_INIT); 164 buildCodeView(CodeCategory.DECLARATION); 165 166 VariableDeclaration decl = codeData.getDeclarationData(); 167 boolean local = decl.local; 168 for (int i=0; i < variableValues.length; i++) { 169 if (variableValues[i] == local) { 170 selectInComboBox(variableCombo, variableStrings[i]); 171 break; 172 } 173 } 174 int modifiers = decl.modifiers; 175 int access = modifiers & (Modifier.PRIVATE|Modifier.PROTECTED|Modifier.PUBLIC); 176 for (int i=0; i < accessValues.length; i++) { 177 if (accessValues[i] == access) { 178 selectInComboBox(accessCombo, accessStrings[i]); 179 break; 180 } 181 } 182 staticCheckBox.setSelected((modifiers & Modifier.STATIC) == Modifier.STATIC); 183 finalCheckBox.setSelected((modifiers & Modifier.FINAL) == Modifier.FINAL); 184 transientCheckBox.setSelected((modifiers & Modifier.TRANSIENT) == Modifier.TRANSIENT); 185 volatileCheckBox.setSelected((modifiers & Modifier.VOLATILE) == Modifier.VOLATILE); 186 accessCombo.setEnabled(!local); 187 staticCheckBox.setEnabled(!local); 188 transientCheckBox.setEnabled(!local); 189 volatileCheckBox.setEnabled(!local); 190 191 if (local) 192 lastLocalModifiers = modifiers; 193 else 194 lastFieldModifiers = modifiers; 195 196 changed = false; 197 198 if (docListener == null) 199 docListener = new DocumentL(); 200 initCodeEditor.getDocument().addDocumentListener(docListener); 201 declareCodeEditor.getDocument().addDocumentListener(docListener); 202 203 initCodeEditor.getDocument().putProperty(Document.StreamDescriptionProperty, documentContext); 204 declareCodeEditor.getDocument().putProperty(Document.StreamDescriptionProperty, documentContext); 205 206 initCodeEditor.setCaretPosition(0); 207 declareCodeEditor.setCaretPosition(0); 208 } 209 210 private void buildCodeView(CodeCategory category) { 211 editBlockInfos.put(category, new EditBlockInfo[codeData.getEditableBlockCount(category)]); 212 int gCount = codeData.getGuardedBlockCount(category); 213 guardBlockInfos.put(category, new GuardBlockInfo[gCount]); 214 215 try { 216 for (int i=0; i < gCount; i++) { 217 addEditableCode(category, i); 218 addGuardedCode(category, i); 219 } 220 if (gCount > 0) 221 addEditableCode(category, gCount); 222 } 223 catch (BadLocationException ex) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 225 } 226 227 getEditor(category).setEnabled(gCount > 0); 228 } 229 230 private void addEditableCode(CodeCategory category, int blockIndex) 231 throws BadLocationException 232 { 233 Document doc = getDocument(category); 234 EditableBlock eBlock = codeData.getEditableBlock(category, blockIndex); 235 boolean lastBlock = blockIndex+1 == codeData.getEditableBlockCount(category); 236 List <EditableLine> lineList = new LinkedList (); 237 int startIndex = doc.getLength(); 238 boolean needLineEnd = false; 239 240 CodeEntry[] entries = eBlock.getEntries(); 241 for (int i=0; i < entries.length; i++) { 242 CodeEntry e = entries[i]; 243 String code = e.getCode(); 244 if (code == null) 245 continue; 246 247 int lineStart = 0; 249 int codeLength = code.length(); 250 for (int j=0; j < codeLength; j++) { 251 char c = code.charAt(j); 252 if (c == '\n' || j+1 == codeLength) { if (needLineEnd) doc.insertString(doc.getLength(), "\n", null); 257 boolean lastLine = lastBlock && i+1 == entries.length && j+1 == codeLength; 258 needLineEnd = c != '\n' && !lastLine; int lineEnd = c == '\n' && lastLine ? j : j+1; int index = doc.getLength(); 261 doc.insertString(index, code.substring(lineStart, lineEnd), null); 262 Position pos = NbDocument.createPosition(doc, index, Position.Bias.Backward); 263 lineList.add(new EditableLine(pos, eBlock, i, lineList)); 264 265 lineStart = j + 1; 266 } 267 } 268 } 269 270 if (lineList.size() > 0) { 271 if (needLineEnd) doc.insertString(doc.getLength(), "\n", null); } 274 else { int index = doc.getLength(); 276 if (!lastBlock) 277 doc.insertString(index, "\n", null); Position pos = NbDocument.createPosition(doc, index, Position.Bias.Backward); 279 lineList.add(new EditableLine(pos, eBlock, eBlock.getPreferredEntryIndex(), lineList)); 280 } 281 282 updateGutterComponents(lineList, doc, startIndex, doc.getLength()); 283 284 EditBlockInfo eInfo = new EditBlockInfo(); 285 eInfo.position = lineList.get(0).getPosition(); 286 eInfo.lines = lineList; 287 getEditInfos(category)[blockIndex] = eInfo; 288 } 289 290 private void addGuardedCode(CodeCategory category, int blockIndex) 291 throws BadLocationException 292 { 293 StyledDocument doc = (StyledDocument ) getDocument(category); 294 GuardedBlock gBlock = codeData.getGuardedBlock(category, blockIndex); 295 GuardBlockInfo gInfo = new GuardBlockInfo(); 296 int index = doc.getLength(); 297 if (gBlock.isCustomized()) { 298 String code = gBlock.getCustomCode(); 299 doc.insertString(index, code, null); 300 if (!code.endsWith("\n")) { doc.insertString(doc.getLength(), "\n", null); } 303 int header = gBlock.getHeaderLength(); 304 int footer = gBlock.getFooterLength(); 305 NbDocument.markGuarded(doc, index, header); 306 NbDocument.markGuarded(doc, doc.getLength() - footer, footer); 307 gInfo.customized = true; 308 } 309 else { 310 String code = gBlock.getDefaultCode(); 311 doc.insertString(index, code, null); 312 if (!code.endsWith("\n")) { doc.insertString(doc.getLength(), "\n", null); } 315 NbDocument.markGuarded(doc, index, doc.getLength()-index); 316 } 317 318 Position pos = NbDocument.createPosition(doc, index, Position.Bias.Forward); 319 gInfo.position = pos; 320 getGuardInfos(category)[blockIndex] = gInfo; 321 322 if (gBlock.isCustomizable()) { 323 String [] items = new String [] { NbBundle.getMessage(CustomCodeView.class, "CTL_GuardCombo_Default"), gBlock.getCustomEntry().getDisplayName() }; 325 JComboBox combo = new JComboBox (items); 326 if (gBlock.isCustomized()) { 328 selectInComboBox(combo, items[1]); 329 combo.setToolTipText(gBlock.getCustomEntry().getToolTipText()); 330 } 331 else { 332 selectInComboBox(combo, items[0]); 333 combo.setToolTipText(NbBundle.getMessage(CustomCodeView.class, "CTL_GuardCombo_Default_Hint")); } 335 combo.addActionListener(new GuardSwitchL(category, blockIndex)); 336 getGutter(doc).add(combo, pos); 337 } 338 } 339 340 343 CustomCodeData retreiveCodeData() { 344 retreiveCodeData(CodeCategory.CREATE_AND_INIT); 345 retreiveCodeData(CodeCategory.DECLARATION); 346 347 VariableDeclaration decl = codeData.getDeclarationData(); 348 boolean local = variableValues[variableCombo.getSelectedIndex()]; 349 int modifiers; 350 if (local != decl.local) { 351 modifiers = local ? lastLocalModifiers : lastFieldModifiers; 352 if (finalCheckBox.isSelected()) modifiers |= Modifier.FINAL; 354 else 355 modifiers &= ~Modifier.FINAL; 356 } 357 else { 358 modifiers = accessValues[accessCombo.getSelectedIndex()]; 359 if (staticCheckBox.isSelected()) 360 modifiers |= Modifier.STATIC; 361 if (finalCheckBox.isSelected()) 362 modifiers |= Modifier.FINAL; 363 if (transientCheckBox.isSelected()) 364 modifiers |= Modifier.TRANSIENT; 365 if (volatileCheckBox.isSelected()) 366 modifiers |= Modifier.VOLATILE; 367 if (local) 368 modifiers &= ~(Modifier.STATIC | Modifier.TRANSIENT | Modifier.VOLATILE); 369 } 370 decl.local = local; 371 decl.modifiers = modifiers; 372 373 return codeData; 374 } 375 376 private void retreiveCodeData(CodeCategory category) { 377 int gCount = codeData.getGuardedBlockCount(category); 378 for (int i=0; i < gCount; i++) { 379 retreiveEditableBlock(category, i); 380 retreiveGuardedBlock(category, i); 381 } 382 if (gCount > 0) 383 retreiveEditableBlock(category, gCount); 384 } 385 386 private void retreiveEditableBlock(CodeCategory category, int index) { 387 CodeEntry[] entries = codeData.getEditableBlock(category, index).getEntries(); 388 for (CodeEntry e : entries) { 389 e.setCode(null); 390 } 391 392 int[] blockBounds = getEditBlockBounds(category, index); 393 Document doc = getDocument(category); 394 395 try { 396 String allCode = doc.getText(blockBounds[0], blockBounds[1]-blockBounds[0]); 397 if (allCode.trim().equals("")) return; 399 400 StringBuilder buf = new StringBuilder (); 401 int selIndex = -1; 402 EditableLine nextLine = null; 403 Iterator <EditableLine> it = getEditInfos(category)[index].lines.iterator(); 404 while (it.hasNext() || nextLine != null) { 405 EditableLine l = nextLine != null ? nextLine : it.next(); 406 int startPos = l.getPosition().getOffset(); 407 int endPos; 408 if (it.hasNext()) { 409 nextLine = it.next(); 410 endPos = nextLine.getPosition().getOffset(); 411 } 412 else { 413 nextLine = null; 414 endPos = blockBounds[1]; 415 } 416 buf.append(doc.getText(startPos, endPos-startPos)); 417 if (nextLine == null || nextLine.getSelectedIndex() != l.getSelectedIndex()) { 418 String code = buf.toString().trim(); 419 if (!code.equals("")) entries[l.getSelectedIndex()].setCode(code); 421 buf.delete(0, buf.length()); 422 } 423 } 424 } 425 catch (BadLocationException ex) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 427 } 428 } 429 430 private void retreiveGuardedBlock(CodeCategory category, int index) { 431 GuardedBlock gBlock = codeData.getGuardedBlock(category, index); 432 if (!gBlock.isCustomizable()) 433 return; 434 435 if (getGuardInfos(category)[index].customized) { 436 Document doc = getDocument(category); 437 int[] blockBounds = getGuardBlockBounds(category, index); 438 try { 439 int startPos = blockBounds[0] + gBlock.getHeaderLength(); 440 String code = doc.getText(startPos, 441 blockBounds[1] - gBlock.getFooterLength() - startPos); 442 gBlock.setCustomizedCode(code); 443 } 444 catch (BadLocationException ex) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 446 } 447 } 448 else { gBlock.setCustomizedCode(null); 450 } 451 } 452 453 private void selectInComboBox(JComboBox combo, Object item) { 454 ignoreComboAction = true; 455 combo.setSelectedItem(item); 456 ignoreComboAction = false; 457 } 458 459 462 private JTextComponent getEditor(CodeCategory category) { 463 switch (category) { 464 case CREATE_AND_INIT: return initCodeEditor; 465 case DECLARATION: return declareCodeEditor; 466 } 467 return null; 468 } 469 470 private Document getDocument(CodeCategory category) { 471 return getEditor(category).getDocument(); 472 } 473 474 private EditBlockInfo[] getEditInfos(CodeCategory category) { 475 return editBlockInfos.get(category); 476 } 477 478 private GuardBlockInfo[] getGuardInfos(CodeCategory category) { 479 return guardBlockInfos.get(category); 480 } 481 482 private JPanel getGutter(Document doc) { 483 if (doc == initCodeEditor.getDocument()) 484 return initGutter; 485 if (doc == declareCodeEditor.getDocument()) 486 return declareGutter; 487 return null; 488 } 489 490 private CodeCategory getCategoryForDocument(Document doc) { 491 if (doc == initCodeEditor.getDocument()) 492 return CodeCategory.CREATE_AND_INIT; 493 if (doc == declareCodeEditor.getDocument()) 494 return CodeCategory.DECLARATION; 495 return null; 496 } 497 498 private static Element getRootElement(Document doc) { 499 return doc.getRootElements()[0]; 500 } 501 502 504 private class EditableLine { 505 private Position position; 506 private JComboBox targetCombo; 507 private List <EditableLine> linesInBlock; 508 private CodeEntry[] codeEntries; 509 510 EditableLine(Position pos, EditableBlock eBlock, int selIndex, List <EditableLine> lines) { 511 position = pos; 512 linesInBlock = lines; 513 codeEntries = eBlock.getEntries(); 514 targetCombo = new JComboBox (codeEntries); 515 setSelectedIndex(selIndex); 516 targetCombo.setToolTipText(codeEntries[selIndex].getToolTipText()); 517 targetCombo.addActionListener(new EditSwitchL()); 518 } 519 520 Position getPosition() { 521 return position; 522 } 523 524 Component getGutterComponent() { 525 return targetCombo; 526 } 527 528 boolean isVisible() { 530 return targetCombo.getParent() != null && targetCombo.isVisible(); 531 } 532 533 int getSelectedIndex() { 534 return targetCombo.getSelectedIndex(); 535 } 536 537 void setSelectedIndex(int index) { 538 selectInComboBox(targetCombo, targetCombo.getItemAt(index)); 539 } 540 541 class EditSwitchL implements ActionListener { 542 public void actionPerformed(ActionEvent e) { 543 if (ignoreComboAction) 544 return; 546 changed = true; 547 int selectedIndex = targetCombo.getSelectedIndex(); 551 boolean preceding = true; 552 for (EditableLine l : linesInBlock) { 553 if (l != EditableLine.this) { 554 if ((preceding && l.getSelectedIndex() > selectedIndex) 555 || (!preceding && l.getSelectedIndex() < selectedIndex)) 556 { l.setSelectedIndex(selectedIndex); 558 } 559 } 560 else preceding = false; 561 } 562 targetCombo.setToolTipText(codeEntries[selectedIndex].getToolTipText()); 563 } 564 } 565 } 566 567 private boolean updateGutterComponents(List <EditableLine> lines, Document doc, 568 int startIndex, int endIndex) 569 { 570 String text; 571 try { 572 text = doc.getText(startIndex, endIndex-startIndex); 573 } 574 catch (BadLocationException ex) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 576 return false; 577 } 578 579 boolean visibility = !text.trim().equals(""); int prevSelectedIndex = 0; 581 boolean changed = false; 582 Container gutter = getGutter(doc); 583 for (EditableLine l : lines) { 584 if (l.getSelectedIndex() < prevSelectedIndex) 586 l.setSelectedIndex(prevSelectedIndex); 587 else 588 prevSelectedIndex = l.getSelectedIndex(); 589 Component comp = l.getGutterComponent(); 591 if (comp.getParent() == null) 592 gutter.add(comp, l.getPosition()); 593 if (visibility != l.isVisible()) { 595 comp.setVisible(visibility); 596 changed = true; 597 } 598 } 599 return changed; 600 } 601 602 605 private class DocumentL implements DocumentListener { 606 boolean active = true; 607 608 public void insertUpdate(DocumentEvent e) { 609 if (active) 610 contentChange(e); 611 } 612 613 public void removeUpdate(DocumentEvent e) { 614 if (active) 615 contentChange(e); 616 } 617 618 public void changedUpdate(DocumentEvent e) { 619 } 620 621 private void contentChange(DocumentEvent e) { 622 changed = true; 623 624 Document doc = e.getDocument(); 625 CodeCategory category = getCategoryForDocument(doc); 626 int eBlockIndex = getEditBlockIndex(category, e.getOffset()); 627 if (eBlockIndex < 0) 628 return; 629 630 List <EditableLine> lines = getEditInfos(category)[eBlockIndex].lines; 631 int[] blockBounds = getEditBlockBounds(category, eBlockIndex); 632 633 boolean repaint = false; 634 DocumentEvent.ElementChange change = e.getChange(getRootElement(doc)); 635 if (change != null) { 636 Element [] added = change.getChildrenAdded(); 637 Element [] removed = change.getChildrenRemoved(); 638 if (added.length != removed.length) { 639 Element rootEl = getRootElement(doc); 640 int elIndex = rootEl.getElementIndex(e.getOffset()); 641 if (added.length > removed.length) { processAddedLines(rootEl, elIndex, lines, blockBounds, 643 codeData.getEditableBlock(category, eBlockIndex)); 644 repaint = true; 645 } 646 else if (added.length < removed.length) { processRemovedLines(rootEl.getElement(elIndex), lines, blockBounds); 648 if (blockBounds[0] == blockBounds[1]) { try { doc.insertString(blockBounds[0], "\n", null); getEditor(category).setCaretPosition(blockBounds[0]); 652 } 653 catch (BadLocationException ex) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 655 } 656 return; } 658 repaint = true; 659 } 660 } 661 } 662 663 repaint |= updateGutterComponents(lines, doc, blockBounds[0], blockBounds[1]); 664 665 if (repaint) { 666 JPanel gutter = getGutter(doc); 667 gutter.revalidate(); 668 gutter.repaint(); 669 } 670 } 671 } 672 673 private void processAddedLines(Element rootEl, int elIndex, 674 List <EditableLine> lines, 675 int[] blockBounds, 676 EditableBlock eBlock) 677 { 678 Document doc = rootEl.getDocument(); 679 int elPos = rootEl.getElement(elIndex).getStartOffset(); 680 681 int endPos = -1; 683 int selIndex = -1; 684 ListIterator <EditableLine> lineIt = lines.listIterator(); 685 while (lineIt.hasNext()) { 686 EditableLine l = lineIt.next(); 687 int pos = l.getPosition().getOffset(); 688 if (pos > elPos) { 689 endPos = pos; 690 lineIt.previous(); 691 break; 692 } 693 else { 694 selIndex = l.getSelectedIndex(); 695 if (pos == elPos) { elIndex++; 697 elPos = rootEl.getElement(elIndex).getStartOffset(); 698 } 699 } 700 } 701 if (endPos < 0) { endPos = blockBounds[1]; 703 } 704 if (selIndex < 0) { 705 selIndex = eBlock.getPreferredEntryIndex(); 706 } 707 708 try { 710 do { 711 Position pos = NbDocument.createPosition(doc, elPos, Position.Bias.Backward); 712 lineIt.add(new EditableLine(pos, eBlock, selIndex, lines)); 713 if (++elIndex >= rootEl.getElementCount()) 714 break; 715 elPos = rootEl.getElement(elIndex).getStartOffset(); 716 } 717 while (elPos < endPos); 718 } 719 catch (BadLocationException ex) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 721 } 722 } 723 724 private void processRemovedLines(Element changeEl, 725 List <EditableLine> lines, 726 int[] blockBounds) 727 { 728 Document doc = changeEl.getDocument(); 729 int startPos = changeEl.getStartOffset(); 730 int endPos = changeEl.getEndOffset(); 731 732 EditableLine firstLine = null; 734 EditableLine lastLine = null; 735 Iterator <EditableLine> it = lines.iterator(); 736 while (it.hasNext()) { 737 EditableLine l = it.next(); 738 int pos = l.getPosition().getOffset(); 739 if (pos >= startPos) { 740 if (pos >= endPos) 741 break; 742 if (firstLine == null) 743 firstLine = l; 744 lastLine = l; 745 } 746 } 747 if (firstLine == null) 748 return; 750 boolean wholeFirstLine = lastLine.getPosition().getOffset() == startPos; 751 boolean mergedToGuarded = startPos == blockBounds[1] && startPos != doc.getLength(); 752 753 it = lines.iterator(); 755 while (it.hasNext() && lastLine != null) { 756 EditableLine l = it.next(); 757 boolean remove; 758 if (l == firstLine) { 759 remove = mergedToGuarded || wholeFirstLine; 760 firstLine = null; 761 } 762 else if (l == lastLine) { 763 remove = mergedToGuarded || !wholeFirstLine; 764 lastLine = null; 765 } 766 else { 767 remove = firstLine == null; } 769 if (remove) { 770 it.remove(); 771 Component comp = l.getGutterComponent(); 772 comp.getParent().remove(comp); 773 } 774 } 775 } 776 777 private int[] getEditBlockBounds(CodeCategory category, int index) { 778 int startIndex = getEditInfos(category)[index].position.getOffset(); 779 GuardBlockInfo[] gInfos = getGuardInfos(category); 780 int endIndex = index < gInfos.length ? 781 gInfos[index].position.getOffset() : 782 getDocument(category).getLength(); 783 return new int[] { startIndex, endIndex }; 784 } 785 786 private int getEditBlockIndex(CodeCategory category, int offset) { 787 return getBlockIndex(category, offset, true); 788 } 789 790 private int getGuardBlockIndex(CodeCategory category, int offset) { 791 return getBlockIndex(category, offset, false); 792 } 793 794 private int getBlockIndex(CodeCategory category, int offset, boolean editable) { 795 EditBlockInfo[] editInfos = getEditInfos(category); 796 GuardBlockInfo[] guardInfos = getGuardInfos(category); 797 for (int i=0; i < guardInfos.length; i++) { 799 int editPos = editInfos[i].position.getOffset(); 800 if (editPos > offset) return editable ? -1 : i-1; 802 if (editPos == offset || guardInfos[i].position.getOffset() >= offset) 803 return editable ? i : -1; } 805 return editable ? editInfos.length-1 : -1; 807 } 808 809 811 private class GuardSwitchL implements ActionListener { 812 CodeCategory category; 813 int blockIndex; 814 815 GuardSwitchL(CodeCategory cat, int index) { 816 category = cat; 817 blockIndex = index; 818 } 819 820 public void actionPerformed(ActionEvent e) { 821 if (ignoreComboAction) 822 return; 824 GuardedBlock gBlock = codeData.getGuardedBlock(category, blockIndex); 825 GuardBlockInfo gInfo = getGuardInfos(category)[blockIndex]; 826 int[] blockBounds = getGuardBlockBounds(category, blockIndex); 827 int startOffset = blockBounds[0]; 828 int endOffset = blockBounds[1]; 829 int gHead = gBlock.getHeaderLength(); 830 int gFoot = gBlock.getFooterLength(); 831 JTextComponent editor = getEditor(category); 832 StyledDocument doc = (StyledDocument ) editor.getDocument(); 833 834 changed = true; 835 836 JComboBox combo = (JComboBox ) e.getSource(); 837 try { 838 docListener.active = false; 839 if (combo.getSelectedIndex() == 1) { NbDocument.unmarkGuarded(doc, startOffset, endOffset - startOffset); 841 doc.remove(startOffset, endOffset - startOffset - 1); 843 String customCode = gBlock.getCustomCode(); 845 int customLength = customCode.length(); 846 if (gInfo.customizedCode != null) { customCode = customCode.substring(0, gHead) 848 + gInfo.customizedCode 849 + customCode.substring(customLength - gFoot); 850 customLength = customCode.length(); 851 } 852 if (customCode.endsWith("\n")) customCode = customCode.substring(0, customLength-1); 854 doc.insertString(startOffset, customCode, null); 855 gInfo.customized = true; 856 NbDocument.markGuarded(doc, startOffset, gHead); 858 NbDocument.markGuarded(doc, startOffset + customLength - gFoot, gFoot); 859 editor.setSelectionStart(startOffset + gHead); 860 editor.setSelectionEnd(startOffset + customLength - gFoot); 861 editor.requestFocus(); 862 combo.setToolTipText(gBlock.getCustomEntry().getToolTipText()); 863 } 864 else { gInfo.customizedCode = doc.getText(startOffset + gHead, 867 endOffset - gFoot - gHead - startOffset); 868 NbDocument.unmarkGuarded(doc, endOffset - gFoot, gFoot); 869 NbDocument.unmarkGuarded(doc, startOffset, gHead); 870 doc.remove(startOffset, endOffset - startOffset - 1); 872 String defaultCode = gBlock.getDefaultCode(); 873 if (defaultCode.endsWith("\n")) defaultCode = defaultCode.substring(0, defaultCode.length()-1); 875 doc.insertString(startOffset, defaultCode, null); 876 gInfo.customized = false; 877 NbDocument.markGuarded(doc, startOffset, defaultCode.length()+1); if (editor.getSelectionStart() >= startOffset && editor.getSelectionEnd() <= endOffset) 880 editor.setCaretPosition(startOffset); 881 combo.setToolTipText(NbBundle.getMessage(CustomCodeData.class, "CTL_GuardCombo_Default_Hint")); } 883 gInfo.position = NbDocument.createPosition(doc, startOffset, Position.Bias.Forward); 885 886 docListener.active = true; 887 } 888 catch (BadLocationException ex) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 890 } 891 } 892 } 893 894 private int[] getGuardBlockBounds(CodeCategory category, int index) { 895 int startIndex = getGuardInfos(category)[index].position.getOffset(); 896 int endIndex = getEditInfos(category)[index+1].position.getOffset(); 897 return new int[] { startIndex, endIndex }; 898 } 899 900 902 private static class GutterLayout implements LayoutManager2 { 903 904 private JTextComponent editor; 905 private Map <Component , Position > positions; 906 private int lineHeight = -1; 907 908 private static final int LEFT_GAP = 2; 909 private static final int RIGHT_GAP = 4; 910 911 GutterLayout(JTextComponent editor, Map <Component , Position > positionMap) { 912 this.editor = editor; 913 this.positions = positionMap; 914 } 915 916 public void addLayoutComponent(Component comp, Object constraints) { 917 positions.put(comp, (Position )constraints); 918 } 919 920 public void layoutContainer(Container parent) { 921 StyledDocument doc = (StyledDocument )editor.getDocument(); 922 for (Component comp : parent.getComponents()) { 923 Position pos = positions.get(comp); 924 int line = NbDocument.findLineNumber(doc, pos.getOffset()); 925 Dimension prefSize = comp.getPreferredSize(); 926 int dy = lineHeight() - prefSize.height; 927 dy = dy > 0 ? dy / 2 + 1 : 0; 928 comp.setBounds(LEFT_GAP, 929 line * lineHeight() + dy, 930 parent.getWidth() - LEFT_GAP - RIGHT_GAP, 931 Math.min(prefSize.height, lineHeight())); 932 } 933 } 934 935 public void removeLayoutComponent(Component comp) { 936 positions.remove(comp); 937 } 938 939 public Dimension preferredLayoutSize(Container parent) { 940 int prefWidth = 0; 941 for (Component comp : positions.keySet()) { 942 Dimension prefSize = comp.getPreferredSize(); 943 if (prefSize.width > prefWidth) 944 prefWidth = prefSize.width; 945 } 946 return new Dimension (prefWidth + LEFT_GAP + RIGHT_GAP, 947 editor.getPreferredSize().height); 948 } 949 950 public Dimension minimumLayoutSize(Container parent) { 951 return preferredLayoutSize(parent); 952 } 953 954 public Dimension maximumLayoutSize(Container parent) { 955 return preferredLayoutSize(parent); 956 } 957 958 public float getLayoutAlignmentX(Container target) { 959 return .5f; 960 } 961 962 public float getLayoutAlignmentY(Container target) { 963 return .5f; 964 } 965 966 public void invalidateLayout(Container target) { 967 } 968 969 public void addLayoutComponent(String name, Component comp) { 970 } 971 972 974 private int lineHeight() { 975 if (lineHeight < 0) { 976 int lines = getLineCount(editor.getDocument()); 977 lineHeight = editor.getPreferredSize().height / lines; 978 } 979 return lineHeight; 980 } 981 } 982 983 private static int getLineCount(Document doc) { 984 return getRootElement(doc).getElementCount(); 985 } 986 987 992 private void initComponents() { 994 javax.swing.JLabel declarationCodeLabel; 995 javax.swing.JLabel initCodeLabel; 996 javax.swing.JLabel selectComponentLabel; 997 javax.swing.JLabel variableAccessLabel; 998 javax.swing.JLabel variableScopeLabel; 999 1000 initCodeLabel = new javax.swing.JLabel (); 1001 jScrollPane1 = new javax.swing.JScrollPane (); 1002 initCodeEditor = new javax.swing.JEditorPane (); 1003 declarationCodeLabel = new javax.swing.JLabel (); 1004 jScrollPane2 = new javax.swing.JScrollPane (); 1005 declareCodeEditor = new javax.swing.JEditorPane (); 1006 selectComponentLabel = new javax.swing.JLabel (); 1007 componentCombo = new javax.swing.JComboBox (); 1008 renameButton = new javax.swing.JButton (); 1009 variableScopeLabel = new javax.swing.JLabel (); 1010 variableCombo = new javax.swing.JComboBox (); 1011 variableAccessLabel = new javax.swing.JLabel (); 1012 accessCombo = new javax.swing.JComboBox (); 1013 staticCheckBox = new javax.swing.JCheckBox (); 1014 finalCheckBox = new javax.swing.JCheckBox (); 1015 transientCheckBox = new javax.swing.JCheckBox (); 1016 volatileCheckBox = new javax.swing.JCheckBox (); 1017 infoLabel = new javax.swing.JLabel (); 1018 1019 FormListener formListener = new FormListener(); 1020 1021 initCodeLabel.setFont(initCodeLabel.getFont().deriveFont(initCodeLabel.getFont().getStyle() | java.awt.Font.BOLD)); 1022 initCodeLabel.setText(org.openide.util.NbBundle.getMessage(CustomCodeView.class, "CustomCodeView.initCodeLabel.text")); 1024 jScrollPane1.setViewportView(initCodeEditor); 1025 1026 declarationCodeLabel.setFont(declarationCodeLabel.getFont().deriveFont(declarationCodeLabel.getFont().getStyle() | java.awt.Font.BOLD)); 1027 declarationCodeLabel.setText(org.openide.util.NbBundle.getMessage(CustomCodeView.class, "CustomCodeView.declarationCodeLabel.text")); 1029 jScrollPane2.setViewportView(declareCodeEditor); 1030 1031 selectComponentLabel.setText(org.openide.util.NbBundle.getMessage(CustomCodeView.class, "CustomCodeView.selectComponentLabel.text")); 1033 componentCombo.addActionListener(formListener); 1034 1035 renameButton.setText(org.openide.util.NbBundle.getMessage(CustomCodeView.class, "CustomCodeView.renameButton.text")); renameButton.addActionListener(formListener); 1037 1038 variableScopeLabel.setText(org.openide.util.NbBundle.getMessage(CustomCodeView.class, "CustomCodeView.variableScopeLabel.text")); 1040 variableCombo.addActionListener(formListener); 1041 1042 variableAccessLabel.setText(org.openide.util.NbBundle.getMessage(CustomCodeView.class, "CustomCodeView.variableAccessLabel.text")); 1044 accessCombo.addActionListener(formListener); 1045 1046 staticCheckBox.setText("static"); staticCheckBox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0)); 1048 staticCheckBox.setMargin(new java.awt.Insets (0, 0, 0, 0)); 1049 staticCheckBox.addActionListener(formListener); 1050 1051 finalCheckBox.setText("final"); finalCheckBox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0)); 1053 finalCheckBox.setMargin(new java.awt.Insets (0, 0, 0, 0)); 1054 finalCheckBox.addActionListener(formListener); 1055 1056 transientCheckBox.setText("transient"); transientCheckBox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0)); 1058 transientCheckBox.setMargin(new java.awt.Insets (0, 0, 0, 0)); 1059 transientCheckBox.addActionListener(formListener); 1060 1061 volatileCheckBox.setText("volatile"); volatileCheckBox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0)); 1063 volatileCheckBox.setMargin(new java.awt.Insets (0, 0, 0, 0)); 1064 volatileCheckBox.addActionListener(formListener); 1065 1066 infoLabel.setText(org.openide.util.NbBundle.getMessage(CustomCodeView.class, "CustomCodeView.infoLabel.text")); 1068 org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this); 1069 this.setLayout(layout); 1070 layout.setHorizontalGroup( 1071 layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) 1072 .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() 1073 .addContainerGap() 1074 .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) 1075 .add(org.jdesktop.layout.GroupLayout.LEADING, jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 652, Short.MAX_VALUE) 1076 .add(org.jdesktop.layout.GroupLayout.LEADING, layout.createSequentialGroup() 1077 .add(variableScopeLabel) 1078 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 1079 .add(variableCombo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) 1080 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 1081 .add(variableAccessLabel) 1082 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 1083 .add(accessCombo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) 1084 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 1085 .add(finalCheckBox) 1086 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 1087 .add(staticCheckBox) 1088 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 1089 .add(transientCheckBox) 1090 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 1091 .add(volatileCheckBox)) 1092 .add(org.jdesktop.layout.GroupLayout.LEADING, jScrollPane2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 652, Short.MAX_VALUE) 1093 .add(org.jdesktop.layout.GroupLayout.LEADING, declarationCodeLabel) 1094 .add(org.jdesktop.layout.GroupLayout.LEADING, layout.createSequentialGroup() 1095 .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) 1096 .add(layout.createSequentialGroup() 1097 .add(selectComponentLabel) 1098 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 1099 .add(componentCombo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) 1100 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 1101 .add(renameButton)) 1102 .add(initCodeLabel)) 1103 .add(20, 20, 20) 1104 .add(infoLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 449, Short.MAX_VALUE))) 1105 .addContainerGap()) 1106 ); 1107 1108 layout.linkSize(new java.awt.Component [] {accessCombo, variableCombo}, org.jdesktop.layout.GroupLayout.HORIZONTAL); 1109 1110 layout.setVerticalGroup( 1111 layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) 1112 .add(layout.createSequentialGroup() 1113 .addContainerGap() 1114 .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) 1115 .add(layout.createSequentialGroup() 1116 .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) 1117 .add(selectComponentLabel) 1118 .add(componentCombo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) 1119 .add(renameButton)) 1120 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 1121 .add(initCodeLabel)) 1122 .add(infoLabel)) 1123 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 1124 .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 348, Short.MAX_VALUE) 1125 .add(11, 11, 11) 1126 .add(declarationCodeLabel) 1127 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 1128 .add(jScrollPane2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 58, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) 1129 .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) 1130 .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) 1131 .add(variableScopeLabel) 1132 .add(variableCombo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) 1133 .add(variableAccessLabel) 1134 .add(accessCombo, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) 1135 .add(staticCheckBox) 1136 .add(finalCheckBox) 1137 .add(transientCheckBox) 1138 .add(volatileCheckBox)) 1139 .addContainerGap()) 1140 ); 1141 } 1142 1143 1145 private class FormListener implements java.awt.event.ActionListener { 1146 FormListener() {} 1147 public void actionPerformed(java.awt.event.ActionEvent evt) { 1148 if (evt.getSource() == componentCombo) { 1149 CustomCodeView.this.componentComboActionPerformed(evt); 1150 } 1151 else if (evt.getSource() == renameButton) { 1152 CustomCodeView.this.renameButtonActionPerformed(evt); 1153 } 1154 else if (evt.getSource() == variableCombo) { 1155 CustomCodeView.this.declControlActionPerformed(evt); 1156 } 1157 else if (evt.getSource() == accessCombo) { 1158 CustomCodeView.this.declControlActionPerformed(evt); 1159 } 1160 else if (evt.getSource() == staticCheckBox) { 1161 CustomCodeView.this.declControlActionPerformed(evt); 1162 } 1163 else if (evt.getSource() == finalCheckBox) { 1164 CustomCodeView.this.declControlActionPerformed(evt); 1165 } 1166 else if (evt.getSource() == transientCheckBox) { 1167 CustomCodeView.this.declControlActionPerformed(evt); 1168 } 1169 else if (evt.getSource() == volatileCheckBox) { 1170 CustomCodeView.this.declControlActionPerformed(evt); 1171 } 1172 } 1173 } 1175 private void declControlActionPerformed(java.awt.event.ActionEvent evt) { if (ignoreComboAction) 1177 return; 1179 changed = true; 1180 controller.declarationChanged(); 1181 } 1183 private void renameButtonActionPerformed(java.awt.event.ActionEvent evt) { controller.renameInvoked(); 1185 } 1187 private void componentComboActionPerformed(java.awt.event.ActionEvent evt) { if (ignoreComboAction) 1189 return; 1191 controller.componentExchanged((String )componentCombo.getSelectedItem()); 1192 } 1194 private javax.swing.JComboBox accessCombo; 1196 private javax.swing.JComboBox componentCombo; 1197 private javax.swing.JEditorPane declareCodeEditor; 1198 private javax.swing.JCheckBox finalCheckBox; 1199 private javax.swing.JLabel infoLabel; 1200 private javax.swing.JEditorPane initCodeEditor; 1201 private javax.swing.JScrollPane jScrollPane1; 1202 private javax.swing.JScrollPane jScrollPane2; 1203 private javax.swing.JButton renameButton; 1204 private javax.swing.JCheckBox staticCheckBox; 1205 private javax.swing.JCheckBox transientCheckBox; 1206 private javax.swing.JComboBox variableCombo; 1207 private javax.swing.JCheckBox volatileCheckBox; 1208 private JPanel initGutter; 1210 private JPanel declareGutter; 1211 1212 private static final boolean[] variableValues = { false, true }; 1213 private static final String [] variableStrings = { 1214 NbBundle.getMessage(CustomCodeView.class, "CTL_VariableCombo_Field"), NbBundle.getMessage(CustomCodeView.class, "CTL_VariableCombo_Local") }; private static final int[] accessValues = { Modifier.PRIVATE, 0, Modifier.PROTECTED, Modifier.PUBLIC }; 1217 private static final String [] accessStrings = { 1218 "private", NbBundle.getMessage(CustomCodeView.class, "CTL_AccessCombo_package_private"), "protected", "public" }; } 1223 | Popular Tags |