001: package tide.outputtabs;
002:
003: import tide.project.*;
004: import tide.sources.*;
005: import tide.editor.*;
006: import snow.utils.storage.*;
007: import snow.utils.*;
008: import snow.texteditor.*;
009: import snow.datatransfer.*;
010: import javax.swing.*;
011: import java.awt.*;
012: import java.awt.event.*;
013: import javax.swing.border.*;
014: import javax.swing.text.*;
015: import java.util.*;
016: import java.io.*;
017: import java.text.*;
018: import java.util.regex.*;
019:
020: /** Used for execution and compiler outputs.
021: * knonw subclasses: tide.execute.ExecutionOutputPanel and tide.compiler.CompilerOutputPanel .
022: */
023: public abstract class OutputTextPanel extends JPanel {
024: public final SimpleDocument doc = new SimpleDocument();
025: protected final JTextPane pane = new JTextPane(doc);
026: protected final SearchPanel searchPanel = new SearchPanel(pane, doc);
027: protected final JScrollPane scrollPane;
028:
029: // cool: double clicking on words selects all same words.
030: final ArrayList<Object> selectedWordTags = new ArrayList<Object>();
031:
032: public OutputTextPanel(boolean editable) {
033: super (new BorderLayout(0, 0));
034: setBorder(null);
035:
036: scrollPane = new JScrollPane(pane);
037: scrollPane.setBorder(null);
038: scrollPane.getViewport().setBorder(null); // [Oct2007]
039:
040: add(scrollPane, BorderLayout.CENTER);
041:
042: add(searchPanel, BorderLayout.SOUTH);
043:
044: pane.setEditable(editable);
045: pane
046: .setFont(new Font("Lucida Sans Typewriter", Font.PLAIN,
047: 11));
048:
049: pane.addMouseListener(new MouseAdapter() {
050: @Override
051: public void mousePressed(MouseEvent me) {
052: if (me.isPopupTrigger()) {
053: showPopup(me);
054: }
055: }
056:
057: @Override
058: public void mouseReleased(MouseEvent me) {
059: if (me.isPopupTrigger()) {
060: showPopup(me);
061: }
062: }
063:
064: @Override
065: public void mouseClicked(MouseEvent me) {
066: if (!me.isPopupTrigger()) {
067: clearAutoSelectedWords();
068: if (me.getClickCount() == 2) {
069: doubleClicked(me);
070: } else {
071: lineClicked(me);
072: }
073: }
074: }
075: });
076:
077: if (!editable) {
078: // pane is not editable, but we let ctrl+V (useful for pasting traces)
079: pane.registerKeyboardAction(new ActionListener() {
080: public void actionPerformed(ActionEvent ae) {
081: String txt = ClipboardUtils
082: .getClipboardStringContent();
083: if (txt != null && txt.length() > 0) {
084: doc.append("\r\n" + txt);
085: }
086: }
087: }, "paste", Accelerators.paste,
088: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
089: } // else already defined
090:
091: this .registerKeyboardAction(
092: new ActionListener() {
093: public void actionPerformed(ActionEvent ae) {
094: String selectedText = "";
095: if ((pane.getSelectionEnd() - pane
096: .getSelectionStart()) > 0) {
097: selectedText = pane.getSelectedText();
098: } else {
099: // detect the word at the cursor
100: selectedText = DocumentUtils.getWordAt(doc,
101: pane.getCaretPosition());
102: }
103: if (selectedText != null) {
104: clearAutoSelectedWords();
105: autoSelectWords(selectedText);
106: }
107: }
108: }, "Highlight all words",
109: Accelerators.highlightAllOccurences,
110: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
111:
112: } // Constructor
113:
114: /** @return all the text.
115: */
116: public String getText() {
117: return doc.getText(); // ok.
118: }
119:
120: public void setEditable(boolean is) {
121: pane.setEditable(is);
122: }
123:
124: public void setText(String txt) {
125: pane.setText(txt);
126: }
127:
128: /** Resets the caret to the top of the pane and scrolls.
129: */
130: public void setCaret0() {
131: pane.setCaretPosition(0);
132: }
133:
134: public void setCaretPosition(int p) {
135: pane.setCaretPosition(p);
136: }
137:
138: /** Sets the caret to the end pane and scrolls.
139: */
140: public void setCaretEnd() {
141: if (EventQueue.isDispatchThread()) {
142: pane.setCaretPosition(doc.getLength());
143: } else {
144: EventQueue.invokeLater(new Runnable() {
145: public void run() {
146: pane.setCaretPosition(doc.getLength());
147: }
148: });
149: }
150: }
151:
152: /** Override this to create custom behaviour.
153: */
154: protected void lineClicked(MouseEvent me) {
155: }
156:
157: /** Override this to create custom behaviour. Now selecting all same words.
158: */
159: protected void doubleClicked(MouseEvent me) {
160: int sl = pane.getSelectionEnd() - pane.getSelectionStart();
161: if (sl > 0 && sl < 1000) {
162: String sel = pane.getSelectedText();
163: // highlight them all !
164: autoSelectWords(sel);
165: }
166: }
167:
168: private void clearAutoSelectedWords() {
169: //System.out.println("Clearing "+selectedWordTags.size()+" sel tags");
170: for (Object o : selectedWordTags) {
171: pane.getHighlighter().removeHighlight(o);
172: }
173: selectedWordTags.clear();
174: searchPanel.setInfoText("");
175: }
176:
177: private void autoSelectWords(String w) {
178: try {
179: int[] visibleBounds = DocumentUtils.getVisibleDocPosBounds(
180: pane, scrollPane);
181:
182: // the quick part first:
183: String part = pane.getText(visibleBounds[0],
184: visibleBounds[1] - visibleBounds[0]);
185: int pos = -1;
186: while ((pos = part.indexOf(w, pos + 1)) >= 0) {
187: selectedWordTags.add(pane.getHighlighter()
188: .addHighlight(pos + visibleBounds[0],
189: pos + visibleBounds[0] + w.length(),
190: doc.autoSelectHighlighter));
191: }
192:
193: // the whole document now (ignoring already performed part)
194:
195: part = doc.getText();
196: //pane.getText(0, doc.getLength()); /// AAAAAAHHH textPane.getText() gives different content!
197: pos = -1;
198: while ((pos = part.indexOf(w, pos + 1)) >= 0) {
199: if (pos <= visibleBounds[0] || pos >= visibleBounds[1]) {
200: selectedWordTags.add(pane.getHighlighter()
201: .addHighlight(pos, pos + w.length(),
202: doc.autoSelectHighlighter));
203: }
204: }
205:
206: searchPanel.setInfoText("" + selectedWordTags.size()
207: + " occurence"
208: + (selectedWordTags.size() == 1 ? "" : "s")
209: + " of \""
210: + StringUtils.shortFormForDisplay(w, 30) + "\"");
211:
212: //System.out.println(""+selectedWordTags.size()+" found, l="+part.length());
213: } catch (Exception e) {
214: e.printStackTrace();
215: }
216: }
217:
218: protected Object actualHighlightTag = null;
219:
220: protected void setHighlightedElementOnly(final Element lineElt) {
221: if (actualHighlightTag != null) {
222: pane.getHighlighter().removeHighlight(actualHighlightTag);
223: }
224:
225: if (lineElt != null) {
226: try {
227: actualHighlightTag = pane.getHighlighter()
228: .addHighlight(lineElt.getStartOffset(),
229: lineElt.getEndOffset(),
230: EditorDocument.errorHighlighter);
231: } catch (Exception e) {
232: e.printStackTrace();
233: }
234: }
235: }
236:
237: /** To override with custom popup !
238: */
239: public void showPopup(MouseEvent me) {
240: JPopupMenu popup = createPopupBase(me);
241: popup.show(pane, me.getX(), me.getY());
242: }
243:
244: /** Defines copy paste ops very useful to paste stacktraces
245: from client exceptions for example...
246: */
247: protected JPopupMenu createPopupBase(MouseEvent me) {
248:
249: JPopupMenu popup = new JPopupMenu("");
250:
251: // the menu is accessed through the context menu (right click) and maybe at another location
252: // than the caret => use the clicked point position to detect the work (if no selection)
253: final int clickedPos = pane.viewToModel(me.getPoint());
254:
255: // copy, paste, paste history
256: SharedUtils.addStandardPopupDocumentActions(popup, doc,
257: searchPanel, pane, clickedPos, true);
258:
259: String selectedText = "";
260: if ((pane.getSelectionEnd() - pane.getSelectionStart()) > 0) {
261: selectedText = pane.getSelectedText();
262: } else {
263: // detect the word at the cursot
264: selectedText = DocumentUtils.getWordAt(doc, clickedPos);
265: }
266:
267: if (selectedText != null && selectedText.length() < 1000) {
268: final String fSel = selectedText;
269: JMenuItem ht = new JMenuItem("Highlight all \""
270: + StringUtils.shortFormForDisplay(selectedText, 70)
271: + "\"");
272: ht.setAccelerator(Accelerators.highlightAllOccurences);
273: popup.addSeparator();
274: popup.add(ht);
275: ht.addActionListener(new ActionListener() {
276: public void actionPerformed(ActionEvent ae) {
277: clearAutoSelectedWords();
278: autoSelectWords(fSel);
279: }
280: });
281: }
282:
283: return popup;
284: }
285:
286: /*
287: public static void main(String[] arguments)
288: {
289: // Proguard
290: testRecognizeStackTrace("contains EventDispatchThread.run:139");
291: }
292:
293: static final Pattern st_proguard = Pattern.compile("\\s*(.*?):(\\d+)");
294: public static void testRecognizeStackTrace(String line)
295: {
296: String id = null;
297: int lineN = -1;
298: Matcher m = st_proguard.matcher(line);
299: if(m.find())
300: {
301: id = m.group(1);
302: if(m.groupCount()>1)
303: {
304: lineN = Integer.parseInt(m.group(2));
305: }
306: }
307: System.out.println("id="+id+", line="+lineN);
308: }*/
309:
310: }
|