001: /*
002: This program is free software; you can redistribute it and/or
003: modify it under the terms of the GNU General Public License
004: as published by the Free Software Foundation; either version 2
005: of the License, or any later version.
006: This program is distributed in the hope that it will be useful,
007: but WITHOUT ANY WARRANTY; without even the implied warranty of
008: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
009: GNU General Public License for more detaProjectTreeSelectionListenerils.
010: You should have received a copy of the GNU General Public License
011: along with this program; if not, write to the Free Software
012: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
013: */
014: package org.acm.seguin.completer;
015:
016: import java.awt.BorderLayout;
017: import java.awt.Component;
018: import java.awt.Color;
019: import java.awt.event.ActionEvent;
020: import java.awt.event.ActionListener;
021:
022: import java.io.File;
023: import java.io.IOException;
024: import java.io.Reader;
025: import java.util.ArrayList;
026: import java.util.ArrayList;
027: import java.util.Enumeration;
028: import java.util.HashMap;
029: import java.util.HashSet;
030: import java.util.Iterator;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.Map;
034: import java.util.Set;
035: import java.util.TreeSet;
036: import java.util.Vector;
037: import java.util.Collection;
038:
039: import javax.swing.JButton;
040: import javax.swing.JFileChooser;
041: import javax.swing.JPanel;
042: import javax.swing.JRootPane;
043: import javax.swing.JTabbedPane;
044: import javax.swing.JTree;
045: import javax.swing.Timer;
046: import javax.swing.ImageIcon;
047: import javax.swing.event.DocumentEvent;
048: import javax.swing.event.DocumentListener;
049: import javax.swing.event.TreeSelectionEvent;
050: import javax.swing.event.TreeSelectionListener;
051: import javax.swing.text.BadLocationException;
052: import javax.swing.text.Position;
053: import javax.swing.text.Segment;
054: import javax.swing.tree.*;
055:
056: import edu.umd.cs.findbugs.DetectorFactoryCollection;
057:
058: import errorlist.DefaultErrorSource;
059: import errorlist.ErrorSource;
060: import org.acm.seguin.ide.command.CommandLineSourceBrowser;
061: import org.acm.seguin.ide.common.ASTViewerPane;
062: import org.acm.seguin.ide.common.CPDDuplicateCodeViewer;
063: import org.acm.seguin.ide.common.CodingStandardsViewer;
064: import org.acm.seguin.ide.common.IDEInterface;
065: import org.acm.seguin.ide.common.IDEPlugin;
066: import org.acm.seguin.ide.common.PackageSelectorPanel;
067: import org.acm.seguin.ide.common.SourceBrowser;
068: import org.acm.seguin.ide.jedit.Navigator;
069: import org.acm.seguin.ide.jedit.action.Action;
070: import org.acm.seguin.ide.jedit.action.HideAction;
071: import org.acm.seguin.ide.jedit.action.ReloadAction;
072: import org.acm.seguin.ide.jedit.action.ReloadAllAction;
073: import org.acm.seguin.ide.jedit.action.ShowAction;
074:
075: import org.acm.seguin.ide.jedit.event.JRefactoryEvent;
076: import org.acm.seguin.ide.jedit.event.JRefactoryListener;
077: import org.acm.seguin.io.AllFileFilter;
078:
079: import net.sourceforge.jrefactory.parser.JavaParser;
080: import net.sourceforge.jrefactory.parser.JavaParserConstants;
081: import net.sourceforge.jrefactory.parser.JavaParserVisitorAdapter;
082: import net.sourceforge.jrefactory.parser.ParseException;
083: import net.sourceforge.jrefactory.parser.TokenMgrError;
084: import net.sourceforge.jrefactory.ast.*;
085:
086: // JRefactory imports
087:
088: import org.acm.seguin.tools.RefactoryInstaller;
089: import org.acm.seguin.uml.loader.ReloaderSingleton;
090:
091: import gnu.regexp.RE;
092: import gnu.regexp.REException;
093: import gnu.regexp.REMatch;
094:
095: import org.acm.seguin.completer.info.*;
096: import org.acm.seguin.completer.popup.*;
097:
098: import org.gjt.sp.jedit.*;
099: import org.gjt.sp.jedit.textarea.*;
100: import org.gjt.sp.jedit.buffer.*;
101:
102: /**
103: * Main GUI for JRefactory
104: *
105: * @author <a href="mailto:JRefactoryPlugin@ladyshot.demon.co.uk">Mike Atkinson</a>
106: * @created 23 July 2003
107: * @version $Id: JRefactory.java,v 1.4 2003/09/25 13:30:36 mikeatkinson Exp $
108: * @since 0.0.1
109: */
110: public final class Completer {
111:
112: static Navigator.NavigatorLogger logger = getLogger(Completer.class);
113: public static final boolean DEBUG = true;
114:
115: Map mapBufferToParser = new HashMap();
116: Timer timerPopup = null;
117: private List buffers;
118: JEditTextArea textArea = null;
119:
120: private final View view;
121: private final Navigator navigator;
122: private boolean popupOnDot;
123: private int popupDelay;
124: private Object popLock = new Object();
125: private BasePopup popup = null;
126: private Buffer buffer = null;
127:
128: // for convenience, we define these here to be set by the init method.
129: int offset = -1;
130: int startOffset = -1;
131: int line = -1;
132: int col = -1;
133: char cursor = '\t';
134: String strLine = null;
135:
136: void init() {
137: textArea = view.getTextArea();
138: buffer = view.getBuffer();
139: offset = textArea.getCaretPosition();
140: line = buffer.getLineOfOffset(offset);
141: startOffset = buffer.getLineStartOffset(line);
142: col = offset - startOffset;
143: cursor = buffer.getText(offset, 1).charAt(0);
144: strLine = buffer.getText(startOffset, col);
145: }
146:
147: public static Navigator.NavigatorLogger getLogger(Class clazz) {
148: return Navigator.getLogger(clazz);
149: }
150:
151: /**
152: * Constructor for the Navigation object
153: *
154: * @param view Description of Parameter
155: * @param navigator Description of Parameter
156: */
157: public Completer(View view, Navigator navigator) {
158: System.out.println("new Navigation(" + view + ")");
159: this .view = view;
160: this .navigator = navigator;
161: reconfigure();
162: }
163:
164: public void reconfigure() {
165: popupOnDot = true; //Config.DOT_POPUP.getAsBoolean();
166: popupDelay = 2000; //Config.POPUP_DELAY_MS.getAsInt();
167: }
168:
169: public boolean lockPopup(BasePopup argPopup) {
170: synchronized (popLock) {
171: boolean hasLock = false;
172: if (popup == null) {
173: popup = argPopup;
174: hasLock = true;
175: }
176: return hasLock;
177: }
178: }
179:
180: public void unlockPopup(BasePopup argPopup) {
181: synchronized (popLock) {
182: if (popup == argPopup) {
183: popup = null;
184: }
185: }
186: }
187:
188: /**Complete the expression at the cursor.*/
189: public void complete() {
190: try {
191: // forced request to open popup
192: init();
193: int parenOffset = -1;
194:
195: // search for last non-whitespace char
196: char prevNonWS = '\t';
197: char c = cursor;
198: for (int i = offset - 1; i >= 0; i--) {
199: c = buffer.getText(i, 1).charAt(0);
200: if (!Character.isWhitespace(c)) {
201: prevNonWS = c;
202: parenOffset = i;
203: break;
204: }
205: }
206: if (cursor != '(' && prevNonWS == '(') {
207: openParenPopup(parenOffset);
208: } else if (ParseUtils.isClassHelp(strLine)) {
209: completeClass();
210: } else { //if (cursor != '.' && prevNonWS == '.') {
211: completeMember();
212: }
213: } catch (NullPointerException e) {
214: logger.error("Error in complete()", e);
215: }
216: }
217:
218: public void signatureHelp() {
219: // forced request to open popup
220: init();
221: int parenOffset = -1;
222:
223: // search for last non-whitespace char
224: char prevNonWS = '\t';
225: char c = cursor;
226: for (int i = offset - 1; i >= 0; i--) {
227: c = buffer.getText(i, 1).charAt(0);
228: if (!Character.isWhitespace(c)) {
229: prevNonWS = c;
230: parenOffset = i;
231: break;
232: }
233: }
234: if (cursor != '(' && prevNonWS == '(') {
235: openParenPopup(parenOffset);
236: }
237: }
238:
239: /**
240:
241: * Description of the Method
242:
243: */
244:
245: public void completeMember() {
246: init();
247: if (popupOnDot && cursor == '.') {
248: // explicit dot was typed and we want popup
249: openDotPopup(offset + 1, "");
250: } else {
251: // partial statement like "str.to"
252: int dot = strLine.lastIndexOf(".");
253: if (dot != -1) {
254: openDotPopup(offset - (strLine.length() - dot) + 1,
255: strLine.substring(dot + 1));
256: }
257: }
258: }
259:
260: public void completeClass() {
261: init();
262: char prev = buffer.getText(offset - 1, 1).charAt(0);
263:
264: boolean isNewCase = ParseUtils.isNewClassStatement(strLine);
265: if (Character.isWhitespace(prev)) {
266: // CASE: keyword<space> (i.e. extends )
267: openClassPopup(offset, "", isNewCase);
268: } else if (ParseUtils.isCatchStatement(strLine)) {
269: // CASE: catch (
270: int mark = strLine.lastIndexOf("(");
271: if (mark != -1) {
272: openClassPopup(offset - (strLine.length() - mark),
273: strLine.substring(mark + 1), isNewCase);
274: }
275: } else {
276: // CASE: keyword<space>PartialName (i.e. throws Foo[BarException])
277: int mark = strLine.lastIndexOf(" ");
278: if (mark != -1) {
279: openClassPopup(offset - (strLine.length() - mark),
280: strLine.substring(mark + 1), isNewCase);
281: }
282: }
283: }
284:
285: void openClassPopup(int offset, String prefix, boolean isNewCase) {
286: logger.msg("ClassPopup: prefix=(" + prefix + ") offset=("
287: + offset + ")");
288: JavaParser docParser = (JavaParser) mapBufferToParser
289: .get(buffer);
290: ClassTable classTable = docParser.getClassTable();
291:
292: boolean allClasses = Config.USE_ALL_PROJECT_CLASSES
293: .getAsBoolean();
294: String strFilter = Config.IMPORT_CLASS_FILTER_OUT_RE
295: .getAsString();
296: Set setImports = getImportClassSet(docParser);
297: Set setClasses = (allClasses ? classTable
298: .getAllClassNames(strFilter) : setImports);
299: logger.msg((allClasses ? "Using all classes except ("
300: + strFilter + ")." : "Using imports only.")
301: + " size", setClasses.size());
302: Vector vecItems = new Vector();
303: for (Iterator it = setClasses.iterator(); it.hasNext();) {
304: vecItems.add(new ClassPopupItem(it.next().toString()));
305: }
306: CodePopup cp = new CodePopup(view, prefix, vecItems, null);
307:
308: // will auto import if config say so and will
309: // display popup message of action.
310: cp.addInsertListener(new ClassPopupItem.ImportInsertListener(
311: setImports, Config.AUTO_IMPORT_CLASSES.getAsBoolean(),
312: !Config.SHOW_CONSTRUCTOR_HELP_AFTER_INSERT
313: .getAsBoolean()));
314:
315: if (Config.SHOW_CONSTRUCTOR_HELP_AFTER_INSERT.getAsBoolean()
316: && isNewCase) {
317: cp.addInsertListener(new SigHelpInsertListener());
318: }
319: cp.show();
320: }
321:
322: class SigHelpInsertListener implements InsertListener {
323: public void insertPerformed(PopupItem item, String prefix,
324: String insertedText, View view) {
325: if (item instanceof ClassPopupItem) {
326: view.getTextArea().userInput('(');
327: }
328: signatureHelp();
329: }
330: }
331:
332: void openDotPopup() {
333: openDotPopup(view.getTextArea().getCaretPosition(), "");
334: }
335:
336: void openDotPopup(int offset, String prefix) {
337: init();
338: logger.msg("DotPopup: prefix=(" + prefix + ") offset=("
339: + offset + ")"); //"test".to
340: String expr = ExpressionFinder.getExpression(buffer, offset); // + 1);
341: if (expr == null) {
342: showMsg("Failed to find expression");
343: } else {
344: // remove the '.'
345: expr = expr.substring(0, expr.length() - 1);
346: JavaParser docParser = (JavaParser) mapBufferToParser
347: .get(buffer);
348: ClassTable classTable = docParser.getClassTable();
349: String type = null;
350: try {
351: type = getTypeAtOffset(docParser, expr, offset);
352: } catch (NullPointerException e) {
353: showMsg("Parse error in buffer.");
354: return;
355: }
356: logger
357: .msg("expression={" + expr + "}, type={" + type
358: + "}");
359: boolean staticMembers = false;
360: if (type.startsWith("*")) {
361: staticMembers = true;
362: type = type.substring(1);
363: }
364:
365: Collection colMemberInfos = null;
366: ClassInfo ciExpression = (ClassInfo) classTable.get(type);
367: ClassInfo ciEnclosing = docParser.getEnclosingClass(
368: line + 1, col);
369:
370: if (ciExpression != null) {
371: logger.msg(ciExpression.getFullName() + " in "
372: + ciEnclosing.getFullName());
373: colMemberInfos = getMemberList(classTable,
374: ciExpression, ciEnclosing, staticMembers, null);
375: }
376:
377: if (colMemberInfos == null) {
378: showMsg("No members found.");
379: } else {
380: // create popup items
381: Vector vecData = new Vector();
382: for (Iterator it = colMemberInfos.iterator(); it
383: .hasNext();) {
384: vecData.add(new MemberPopupItem((MemberInfo) it
385: .next()));
386: }
387: CodePopup cp = new CodePopup(view, prefix, vecData,
388: ciExpression.getFullName());
389: if (Config.SHOW_SIG_HELP_AFTER_INSERT.getAsBoolean()) {
390: cp.addInsertListener(new SigHelpInsertListener());
391: }
392: cp.show();
393: }
394: }
395: }
396:
397: void showMsg(String argMsg) {
398: logger.msg(argMsg);
399: SuicidalMsgPopup sp = new SuicidalMsgPopup(view, argMsg, 3000);
400: sp.show();
401: }
402:
403: String getTypeAtCursor() {
404: String str = Test.FOO;
405: init();
406: String type = null;
407: String word2 = buffer
408: .getText(startOffset, offset - startOffset);
409:
410: // get word
411: textArea.selectWord();
412:
413: String word = textArea.getSelectedText();
414:
415: textArea.setCaretPosition(offset);
416:
417: if (word != null && !word.trim().equals("")) {
418: JavaParser parser = (JavaParser) mapBufferToParser
419: .get(buffer);
420: type = getTypeAtOffset(parser, word, offset);
421: if (type != null && !type.trim().equals("")) {
422: type = type.replace('$', '.');
423: if (type.startsWith("*")) {
424: type = type.substring(1);
425: }
426: }
427: logger.msg("word", word);
428: logger.msg("type", type);
429:
430: logger.msg("word2", word2);
431: logger.msg("type2", getTypeAtOffset(parser, word2, offset));
432: }
433: return type;
434: }
435:
436: void showTypeAtCursor() {
437: String type = getTypeAtCursor();
438: if (type != null && !type.trim().equals("")) {
439: PointPopup pp = new PointPopup(view, type);
440: pp.show();
441: /* OLD
442: SuicidalMsgPopup sp = new SuicidalMsgPopup(
443: _view, strType, 3000, Color.blue, Color.white);
444: sp.show();
445: */
446: } else {
447: showMsg("Type not known");
448: }
449: }
450:
451: String getTypeAtOffset(JavaParser parser, String expression,
452: int offset) {
453: int line = textArea.getLineOfOffset(offset);
454: int col = offset - textArea.getLineStartOffset(line);
455: return expressionParser.parseExpression(expression,
456: new SourceLocation(parser.getPath(), line + 1, col),
457: parser);
458: }
459:
460: String getTypeFromImports(JavaParser parser, String name) {
461: // the name should now be the unqualified class name
462: // so we can just look it up classTable and cross reference
463: // it with the imports to find the class!
464: String type = "";
465: String fullName = null;
466: Set imports = getImportClassSet(parser);
467: for (Iterator it = imports.iterator(); it.hasNext();) {
468: fullName = (String) it.next();
469: if (fullName.endsWith("." + name) || fullName.equals(name)) {
470: type = fullName;
471: }
472: }
473: return type;
474: }
475:
476: ClassInfo getEnclosingClassAtOffset(JavaParser parser, int offset) {
477: int line = textArea.getLineOfOffset(offset);
478: int col = offset - textArea.getLineStartOffset(line);
479: return parser.getEnclosingClass(line + 1, col);
480: }
481:
482: void openParenPopup(int parenOffset) {
483: init();
484: String name = null;
485: String type = null;
486: int lookBack = 100;
487: int start = Math.max(0, offset - lookBack);
488: name = buffer.getText(start, offset - start + 1);
489: if (DEBUG) {
490: logger.msg("100 chars back", name);
491: }
492: if (name != null) {
493: JavaParser docParser = (JavaParser) mapBufferToParser
494: .get(buffer);
495: ClassTable classTable = docParser.getClassTable();
496: REMatch match = ParseUtils.getLastMatch(
497: ParseUtils.RE_PAREN_NEW, name);
498: if (ParseUtils.isValidMatch(match, start, parenOffset)) {
499: // found possible constructor [i.e. new String( ]
500: name = match.toString();
501: name = name.substring(3, name.length() - 1).trim();
502: logger.msg("cons, name", name);
503: type = getTypeFromImports(docParser, name);
504: //logger.msg("type", type);
505: ClassInfo ci = classTable.get(type);
506: if (ci != null) {
507: SignaturePopup.showConstructorPopup(view, ci);
508: } else {
509: showMsg("Could not find construtor class info ("
510: + name + ")");
511: }
512: return;
513: }
514: match = ParseUtils.getLastMatch(ParseUtils.RE_PAREN_METHOD,
515: name);
516: if (ParseUtils.isValidMatch(match, start, parenOffset)) {
517: // found possible constructor: new ClassName(
518: name = match.toString();
519: name = name.substring(1, name.length() - 1).trim();
520: int adjustedOffset = start + match.getStartIndex() + 1;
521: String expr = ExpressionFinder.getExpression(buffer,
522: adjustedOffset);
523: if (expr != null) {
524: expr = expr.substring(0, expr.length() - 1);
525: // remove the '.'
526: try {
527: type = getTypeAtOffset(docParser, expr,
528: adjustedOffset);
529: } catch (NullPointerException e) {
530: showMsg("Parse error in buffer.");
531: return;
532: }
533: //type = getTypeAtOffset(docParser, expr, iAdjustedOffset);
534: boolean staticOnly = false;
535: if (type.startsWith("*")) {
536: staticOnly = true;
537: type = type.substring(1);
538: }
539: ClassInfo ci = classTable.get(type);
540: if (ci != null) {
541: // method help
542: ClassInfo enclosingClass = getEnclosingClassAtOffset(
543: docParser, adjustedOffset);
544: Collection members = getMemberList(classTable,
545: ci, enclosingClass, staticOnly, name);
546: SignaturePopup.showMethodPopup(view, members,
547: ci.getFullName());
548: } else {
549: showMsg("Could not find class info for ("
550: + name + ")");
551: }
552: }
553: return;
554: }
555: match = ParseUtils.getLastMatch(
556: ParseUtils.RE_PAREN_METHOD_THIS, name);
557: if (ParseUtils.isValidMatch(match, start, parenOffset)) {
558: // found possible method call to local class [eg, this]
559: //} else if ( isClassHelpCase(strLine)) {
560: //} else if (isClassHelpCase(strLine)) {
561: // rip off trailing open paren
562: name = name.substring(0, name.lastIndexOf("(")).trim();
563: for (int i = name.length() - 1; i >= 0; i--) {
564: if (!Character.isJavaIdentifierPart(name.charAt(i))) {
565: name = name.substring(i + 1);
566: break;
567: }
568: }
569: logger.msg("local method", name);
570: ClassInfo ci = getEnclosingClassAtOffset(docParser,
571: parenOffset);
572: // return both static and non-static methods
573: Collection members = getMemberList(classTable, ci, ci,
574: false, name);
575: members.addAll(getMemberList(classTable, ci, ci, true,
576: name));
577: SignaturePopup.showMethodPopup(view, members, ci
578: .getFullName());
579: return;
580: }
581: }
582: }
583:
584: private static Collection getMemberList(ClassTable argClassTable,
585: ClassInfo ci, ClassInfo fci, boolean staticMembers,
586: String methodName) {
587: Set setMembers = new TreeSet();
588: try {
589: findMemberList(argClassTable, ci, fci, staticMembers,
590: setMembers, methodName);
591: } catch (Exception e) {
592: logger.error("Error finding members", e);
593: }
594: return setMembers;
595: }
596:
597: private static void findMemberList(ClassTable argClassTable,
598: ClassInfo ci, ClassInfo fci, boolean staticMembers,
599: Collection argMembersCol, String methodName) {
600:
601: if (methodName == null) {
602: for (Iterator i = ci.getClasses().iterator(); i.hasNext();) {
603: MemberInfo mi = (MemberInfo) argClassTable.get(ci
604: .getFullName()
605: + '$' + i.next().toString());
606: //ci.getFullName() + '$' + (String) i.next());
607: if (mi != null
608: && argClassTable.isAccessAllowed(fci, mi,
609: staticMembers, false)) {
610: argMembersCol.add(mi);
611: }
612: }
613: for (Iterator i = ci.getFields().iterator(); i.hasNext();) {
614: MemberInfo mi = (MemberInfo) i.next();
615: //logger.msg("methodName=null,fields", mi.getName());
616: if (argClassTable.isAccessAllowed(fci, mi,
617: staticMembers, false)) {
618: argMembersCol.add(mi);
619: }
620: }
621: }
622:
623: for (Iterator i = ci.getMethods().iterator(); i.hasNext();) {
624: MemberInfo mi = (MemberInfo) i.next();
625: //logger.msg("methodName=null,methods-" + ci.getFullName() , mi.getName());
626: if (methodName == null || methodName.equals(mi.getName())) {
627: if (argClassTable.isAccessAllowed(fci, mi,
628: staticMembers, false)) {
629: argMembersCol.add(mi);
630: }
631: }
632: }
633:
634: String[] ifs = ci.getInterfaces();
635: String sc = ci.getSuperclass();
636: for (int i = 0; i < ifs.length; i++) {
637: ci = argClassTable.get(ifs[i]);
638: if (ci != null) {
639: findMemberList(argClassTable, ci, fci, staticMembers,
640: argMembersCol, methodName);
641: }
642: }
643: // resist getting java.lang.Object methods for arrays...only length
644: if (sc != null && !ci.getFullName().endsWith("[]")) {
645: ci = argClassTable.get(sc);
646: if (ci != null) {
647: findMemberList(argClassTable, ci, fci, staticMembers,
648: argMembersCol, methodName);
649: }
650: }
651: }
652:
653: static Set getImportClassSet(JavaParser argParser) {
654: TreeSet set = new TreeSet();
655: String strImports[] = argParser.getImports();
656: ClassTable classTable = argParser.getClassTable();
657: List listClasses;
658: String strImport;
659: String strPkg;
660:
661: for (int i = 0, l = strImports.length; i < l; i++) {
662: strImport = strImports[i];
663: if (strImport.endsWith(".*")) {
664: listClasses = classTable
665: .getAllClassesInPackage(strImport);
666: for (Iterator it = listClasses.iterator(); it.hasNext();) {
667: set.add(it.next());
668: }
669: } else {
670: set.add(strImport);
671: }
672: }
673: return set;
674: }
675:
676: /**
677: * Description of the Method
678: *
679: * @param buffer Description of the Parameter
680: * @param startLine Description of the Parameter
681: * @param offset Description of the Parameter
682: * @param numLines Description of the Parameter
683: * @param length Description of the Parameter
684: */
685: public void contentInserted(Buffer buffer, int startLine,
686: int offset, int numLines, int length) {
687: if (length != 1) {
688: return;
689: }
690: try {
691: char c = buffer.getText(offset, 1).charAt(0);
692: if (jEdit.getActiveView() == view && popupOnDot && c == '.') {
693: JEditTextArea textArea = view.getTextArea();
694: //if (!isInComment(textArea(), startLine)) {
695: if (ParseUtils.isCodeLine(textArea, startLine)) {
696: //if (!isInComment(jEdit.getActiveView().getTextArea(), startLine)) {
697: if (timerPopup == null) {
698: // This delay is to keep the popup from
699: // opening when a macro is executing (many fast
700: // keystrokes. 50 should be a minimum.
701: // User may set higher.
702: timerPopup = new Timer(popupDelay,
703: new PopupOpener());
704: timerPopup.start();
705: } else {
706: timerPopup.restart();
707: }
708: } else if (timerPopup != null) {
709: if (timerPopup.isRunning()) {
710: timerPopup.stop();
711: }
712: timerPopup = null;
713: }
714: }
715: } catch (Exception ex) {
716: logger.warning("Error responding to Content Insert: ["
717: + "buffer=" + buffer.getName() + ",line="
718: + startLine + "]", ex);
719: }
720: }
721:
722: private class PopupOpener implements Runnable, ActionListener {
723: /**
724: * Description of the Method
725: *
726: * @param event Description of the Parameter
727: */
728: public void actionPerformed(ActionEvent event) {
729: run();
730: }
731:
732: /** Main processing method for the PopupOpener object */
733: public void run() {
734: if (timerPopup != null && timerPopup.isRunning()) {
735: timerPopup.stop();
736: }
737: timerPopup = null;
738: openDotPopup();
739: }
740: }
741: }
|