/* * Copyright (C) 2012 Sony Mobile Communications AB * * This file is part of ApkAnalyser. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package analyser.gui; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.HashMap; import java.util.Map; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTextPane; import javax.swing.SwingUtilities; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.text.DefaultHighlighter; import javax.swing.text.DefaultStyledDocument; import javax.swing.text.Element; import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; import javax.swing.text.Utilities; public class TextBuilder { protected JTextPane pane = new JTextPane(); protected JScrollPane scrollPane; protected int curSearchPos = 0; protected static String curSearchString = null; protected int curLine = 0; protected LineBuilder lineBuilder = null; protected JPopupMenu popup = null; // TODO not thread safe protected Highlighter.HighlightPainter lineHighlightPainter = new LineHighlightPainter(new Color(0, 255, 255, 48)); Object ownerData; // ugly bugly protected static Map<Object, JPopupMenu> popups = new HashMap<Object, JPopupMenu>(); protected static Object popupReference = null; public JTextPane getTextPane() { return pane; } public TextBuilder(LineBuilder lb) { super(); initListener(); init(lb); } public TextBuilder(String text) { super(); initListener(); init(text); } public void init(LineBuilder lb) { curSearchPos = 0; lineBuilder = lb; updateDocument(); setCaretPosition(0); } public void init(String text) { curSearchPos = 0; pane.setText(text); setCaretPosition(0); } private void initListener() { pane.addCaretListener(new CaretListener() { @Override public void caretUpdate(CaretEvent ce) { int dot = ce.getDot(); curLine = pane.getDocument().getDefaultRootElement().getElementIndex(dot); highlightCurrentRow(pane); } }); pane.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent me) { if (popup != null) { // TODO not thread safe popup.setVisible(false); popup = null; } int offset = pane.viewToModel(SwingUtilities.convertPoint(me.getComponent(), me.getPoint(), pane)); setCaretPosition(offset); highlightCurrentRow(pane); if (lineBuilder != null) { int line = pane.getDocument().getDefaultRootElement().getElementIndex(offset); Object ref = null; ref = lineBuilder.getReference(line); Selection.setSelectedObject(TextBuilder.this, ref); if (SwingUtilities.isRightMouseButton(me)) { popupReference = ref; if (ref == null) { ref = void.class; } else { ref = ref.getClass(); } JPopupMenu pu = getPopup(ref); if (pu == null) { pu = getPopup(void.class); } if (pu != null) { pu.show(me.getComponent(), me.getX(), me.getY()); popup = pu; } } else if (SwingUtilities.isLeftMouseButton(me) && me.getClickCount() == 1) { if (ref != null && ref instanceof LineBuilderFormatter.QuickLink) { LineBuilderFormatter.Link link = (LineBuilderFormatter.Link) ref; link.getLinkedAction().actionPerformed(new ActionEvent(link, 0, null)); } } else if (SwingUtilities.isLeftMouseButton(me) && me.getClickCount() == 2) { if (ref != null && ref instanceof LineBuilderFormatter.Link) { LineBuilderFormatter.Link link = (LineBuilderFormatter.Link) ref; link.getLinkedAction().actionPerformed(new ActionEvent(link, 0, null)); } } } } }); // Add keylistener for Search dialog pane.addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { if ((e.getModifiers() & KeyEvent.CTRL_MASK) > 0 && e.getKeyCode() == KeyEvent.VK_F) { String s = (String) JOptionPane.showInputDialog( pane.getParent(), "", "Search", JOptionPane.QUESTION_MESSAGE, null, null, (curSearchString == null ? "" : curSearchString)); if (s != null) { curSearchString = s; curSearchPos = 0; findNext(curSearchString); pane.repaint(); } } else if (e.getKeyCode() == KeyEvent.VK_F3) { if (curSearchString != null) { if ((e.getModifiers() & KeyEvent.SHIFT_MASK) > 0) { findPrev(curSearchString); } else { findNext(curSearchString); } pane.repaint(); } } } @Override public void keyReleased(KeyEvent e) { } @Override public void keyTyped(KeyEvent e) { } }); pane.setEditable(false); } public static void registerPopup(Object o, JPopupMenu popup) { popups.put(o, popup); } /** * @return */ public static Object getPopupReference() { return popupReference; } public static JPopupMenu getPopup(Object o) { return popups.get(o); } public int getCurrentLine() { return curLine; } public void updateDocument() { DefaultStyledDocument newDoc = new DefaultStyledDocument(); lineBuilder.toDocument(newDoc); pane.setDocument(newDoc); } /** * @return */ public LineBuilder getLineBuilder() { return lineBuilder; } public void setEditable(boolean editable) { pane.setEditable(editable); } public void setText(String text) { pane.setText(text); } public int getCaretPosition() { return pane.getCaretPosition(); } public void setCaretPosition(int pos) { pane.setCaretPosition(pos); curLine = pane.getDocument().getDefaultRootElement().getElementIndex( pos); highlightCurrentRow(pane); } public void highlightCurrentRow(JTextComponent textComp) { // First remove all old highlights removeHighlights(textComp); try { Highlighter hilite = textComp.getHighlighter(); // Find start index to highlight Element elem = Utilities.getParagraphElement(pane, pane.getCaretPosition()); int start = elem.getStartOffset(); int end = elem.getEndOffset(); hilite.addHighlight(start, end, lineHighlightPainter); } catch (Throwable ignore) { } } // Removes only our private highlights public void removeHighlights(JTextComponent textComp) { Highlighter hilite = textComp.getHighlighter(); Highlighter.Highlight[] hilites = hilite.getHighlights(); for (int i = 0; i < hilites.length; i++) { if (hilites[i].getPainter() instanceof LineHighlightPainter) { hilite.removeHighlight(hilites[i]); } } } // Search functions public void findNext(String search) { String text = pane.getText(); curSearchPos = text.indexOf(search, curSearchPos + 1); int selPos = curSearchPos; if (curSearchPos >= 0) { for (int i = 0; i < curSearchPos; i++) { if (text.charAt(i) == '\n') { selPos--; } } setCaretPosition(selPos); pane.setSelectionStart(selPos); pane.setSelectionEnd(selPos + search.length()); } else { java.awt.Toolkit.getDefaultToolkit().beep(); pane.setSelectionStart(0); pane.setSelectionEnd(0); curSearchPos = 0; removeHighlights(pane); } } public void findPrev(String search) { String text = pane.getText(); int br = curSearchPos - 1; if (br < 0) { br = 0; } curSearchPos = text.substring(0, br).lastIndexOf(search); int selPos = curSearchPos; if (curSearchPos >= 0) { for (int i = 0; i < curSearchPos; i++) { if (text.charAt(i) == '\n') { selPos--; } } setCaretPosition(selPos); pane.setSelectionStart(selPos); pane.setSelectionEnd(selPos + search.length()); } else { java.awt.Toolkit.getDefaultToolkit().beep(); pane.setSelectionStart(text.length() - 1); pane.setSelectionEnd(text.length() - 1); curSearchPos = text.length() - 1; removeHighlights(pane); } } class LineHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter { public LineHighlightPainter(Color color) { super(color); } } /** * @return */ public Object getOwnerData() { return ownerData; } /** * @param ownerData */ public void setOwnerData(Object ownerData) { this.ownerData = ownerData; } /** * @param scrollPane */ public void setScrollPane(JScrollPane scrollPane) { this.scrollPane = scrollPane; } /** * @return */ public JScrollPane getScrollPane() { return scrollPane; } }