001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jface.internal.text.link.contentassist;
011:
012: import org.eclipse.swt.events.SelectionEvent;
013: import org.eclipse.swt.events.SelectionListener;
014: import org.eclipse.swt.graphics.Point;
015: import org.eclipse.swt.graphics.Rectangle;
016: import org.eclipse.swt.widgets.Control;
017: import org.eclipse.swt.widgets.Table;
018: import org.eclipse.swt.widgets.TableItem;
019:
020: import org.eclipse.core.runtime.Assert;
021:
022: import org.eclipse.jface.text.AbstractInformationControlManager;
023: import org.eclipse.jface.text.IInformationControl;
024: import org.eclipse.jface.text.IInformationControlCreator;
025: import org.eclipse.jface.text.contentassist.ICompletionProposal;
026: import org.eclipse.jface.text.contentassist.ICompletionProposalExtension3;
027:
028: /**
029: * Displays the additional information available for a completion proposal.
030: *
031: * @since 2.0
032: */
033: class AdditionalInfoController2 extends
034: AbstractInformationControlManager implements Runnable {
035:
036: /**
037: * Internal table selection listener.
038: */
039: private class TableSelectionListener implements SelectionListener {
040:
041: /*
042: * @see SelectionListener#widgetSelected(SelectionEvent)
043: */
044: public void widgetSelected(SelectionEvent e) {
045: handleTableSelectionChanged();
046: }
047:
048: /*
049: * @see SelectionListener#widgetDefaultSelected(SelectionEvent)
050: */
051: public void widgetDefaultSelected(SelectionEvent e) {
052: }
053: }
054:
055: /** The proposal table */
056: private Table fProposalTable;
057: /** The thread controlling the delayed display of the additional info */
058: private Thread fThread;
059: /** Indicates whether the display delay has been reset */
060: private boolean fIsReset = false;
061: /** Object to synchronize display thread and table selection changes */
062: private final Object fMutex = new Object();
063: /** Thread access lock. */
064: private final Object fThreadAccess = new Object();
065: /** Object to synchronize initial display of additional info */
066: private Object fStartSignal;
067: /** The table selection listener */
068: private SelectionListener fSelectionListener = new TableSelectionListener();
069: /** The delay after which additional information is displayed */
070: private int fDelay;
071:
072: /**
073: * Creates a new additional information controller.
074: *
075: * @param creator the information control creator to be used by this controller
076: * @param delay time in milliseconds after which additional info should be displayed
077: */
078: AdditionalInfoController2(IInformationControlCreator creator,
079: int delay) {
080: super (creator);
081: fDelay = delay;
082: setAnchor(ANCHOR_RIGHT);
083: setFallbackAnchors(new Anchor[] { ANCHOR_RIGHT, ANCHOR_LEFT,
084: ANCHOR_BOTTOM });
085: }
086:
087: /*
088: * @see AbstractInformationControlManager#install(Control)
089: */
090: public void install(Control control) {
091:
092: if (fProposalTable == control) {
093: // already installed
094: return;
095: }
096:
097: super .install(control);
098:
099: Assert.isTrue(control instanceof Table);
100: fProposalTable = (Table) control;
101: fProposalTable.addSelectionListener(fSelectionListener);
102: synchronized (fThreadAccess) {
103: if (fThread != null)
104: fThread.interrupt();
105: fThread = new Thread(this , ContentAssistMessages
106: .getString("InfoPopup.info_delay_timer_name")); //$NON-NLS-1$
107:
108: fStartSignal = new Object();
109: synchronized (fStartSignal) {
110: fThread.start();
111: try {
112: // wait until thread is ready
113: fStartSignal.wait();
114: } catch (InterruptedException x) {
115: }
116: }
117: }
118: }
119:
120: /*
121: * @see AbstractInformationControlManager#disposeInformationControl()
122: */
123: public void disposeInformationControl() {
124:
125: synchronized (fThreadAccess) {
126: if (fThread != null) {
127: fThread.interrupt();
128: fThread = null;
129: }
130: }
131:
132: if (fProposalTable != null && !fProposalTable.isDisposed()) {
133: fProposalTable.removeSelectionListener(fSelectionListener);
134: fProposalTable = null;
135: }
136:
137: super .disposeInformationControl();
138: }
139:
140: /*
141: * @see java.lang.Runnable#run()
142: */
143: public void run() {
144: try {
145: while (true) {
146:
147: synchronized (fMutex) {
148:
149: if (fStartSignal != null) {
150: synchronized (fStartSignal) {
151: fStartSignal.notifyAll();
152: fStartSignal = null;
153: }
154: }
155:
156: // Wait for a selection event to occur.
157: fMutex.wait();
158:
159: while (true) {
160: fIsReset = false;
161: // Delay before showing the popup.
162: fMutex.wait(fDelay);
163: if (!fIsReset)
164: break;
165: }
166: }
167:
168: if (fProposalTable != null
169: && !fProposalTable.isDisposed()) {
170: fProposalTable.getDisplay().asyncExec(
171: new Runnable() {
172: public void run() {
173: if (!fIsReset)
174: showInformation();
175: }
176: });
177: }
178:
179: }
180: } catch (InterruptedException e) {
181: }
182:
183: synchronized (fThreadAccess) {
184: // only null fThread if it is us!
185: if (Thread.currentThread() == fThread)
186: fThread = null;
187: }
188: }
189:
190: /**
191: *Handles a change of the line selected in the associated selector.
192: */
193: public void handleTableSelectionChanged() {
194:
195: if (fProposalTable != null && !fProposalTable.isDisposed()
196: && fProposalTable.isVisible()) {
197: synchronized (fMutex) {
198: fIsReset = true;
199: fMutex.notifyAll();
200: }
201: }
202: }
203:
204: /*
205: * @see AbstractInformationControlManager#computeInformation()
206: */
207: protected void computeInformation() {
208:
209: if (fProposalTable == null || fProposalTable.isDisposed())
210: return;
211:
212: TableItem[] selection = fProposalTable.getSelection();
213: if (selection != null && selection.length > 0) {
214:
215: TableItem item = selection[0];
216:
217: // compute information
218: String information = null;
219: Object d = item.getData();
220:
221: if (d instanceof ICompletionProposal) {
222: ICompletionProposal p = (ICompletionProposal) d;
223: information = p.getAdditionalProposalInfo();
224: }
225:
226: if (d instanceof ICompletionProposalExtension3)
227: setCustomInformationControlCreator(((ICompletionProposalExtension3) d)
228: .getInformationControlCreator());
229: else
230: setCustomInformationControlCreator(null);
231:
232: // compute subject area
233: setMargins(4, -1);
234: Rectangle area = fProposalTable.getBounds();
235: area.x = 0; // subject area is the whole subject control
236: area.y = 0;
237:
238: // set information & subject area
239: setInformation(information, area);
240: }
241: }
242:
243: /*
244: * @see org.eclipse.jface.text.AbstractInformationControlManager#computeSizeConstraints(Control, IInformationControl)
245: */
246: protected Point computeSizeConstraints(Control subjectControl,
247: IInformationControl informationControl) {
248: Point sizeConstraint = super .computeSizeConstraints(
249: subjectControl, informationControl);
250: Point size = subjectControl.getSize();
251: if (sizeConstraint.x < size.x)
252: sizeConstraint.x = size.x;
253: if (sizeConstraint.y < size.y)
254: sizeConstraint.y = size.y;
255: return sizeConstraint;
256: }
257: }
|