001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 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: * Max Weninger <max.weninger@windriver.com> - https://bugs.eclipse.org/bugs/show_bug.cgi?id=148898
011: *******************************************************************************/package org.eclipse.ui.texteditor;
012:
013: import java.util.ResourceBundle;
014:
015: import org.eclipse.swt.events.DisposeEvent;
016: import org.eclipse.swt.events.DisposeListener;
017: import org.eclipse.swt.widgets.Shell;
018:
019: import org.eclipse.core.runtime.Assert;
020:
021: import org.eclipse.jface.text.IFindReplaceTarget;
022:
023: import org.eclipse.ui.IPartListener;
024: import org.eclipse.ui.IPartService;
025: import org.eclipse.ui.IWorkbenchPart;
026: import org.eclipse.ui.IWorkbenchPartSite;
027: import org.eclipse.ui.IWorkbenchWindow;
028:
029: /**
030: * An action which opens a Find/Replace dialog.
031: * The dialog while open, tracks the active workbench part
032: * and retargets itself to the active find/replace target.
033: * <p>
034: * It can also be used without having an IWorkbenchPart e.g. for
035: * dialogs or wizards by just providing a {@link Shell} and an {@link IFindReplaceTarget}.
036: * <em>In this case the dialog won't be shared with the one
037: * used for the active workbench part.</em>
038: * </p>
039: * <p>
040: * This class may be instantiated; it is not intended to be subclassed.
041: * </p>
042: *
043: * @see IFindReplaceTarget
044: */
045: public class FindReplaceAction extends ResourceAction implements
046: IUpdate {
047:
048: /**
049: * Represents the "global" find/replace dialog. It tracks the active
050: * part and retargets the find/replace dialog accordingly. The find/replace
051: * target is retrieved from the active part using
052: * <code>getAdapter(IFindReplaceTarget.class)</code>.
053: * <p>
054: * The stub has the same life cycle as the find/replace dialog.</p>
055: * <p>
056: * If no IWorkbenchPart is available a Shell must be provided
057: * In this case the IFindReplaceTarget will never change.</p>
058: */
059: static class FindReplaceDialogStub implements IPartListener,
060: DisposeListener {
061:
062: /** The workbench part */
063: private IWorkbenchPart fPart;
064: /** The previous workbench part */
065: private IWorkbenchPart fPreviousPart;
066: /** The previous find/replace target */
067: private IFindReplaceTarget fPreviousTarget;
068:
069: /** The workbench window */
070: private IWorkbenchWindow fWindow;
071: /** The find/replace dialog */
072: private FindReplaceDialog fDialog;
073:
074: /**
075: * Creates a new find/replace dialog accessor anchored at the given part site.
076: *
077: * @param site the part site
078: */
079: public FindReplaceDialogStub(IWorkbenchPartSite site) {
080: this (site.getShell());
081: fWindow = site.getWorkbenchWindow();
082: IPartService service = fWindow.getPartService();
083: service.addPartListener(this );
084: partActivated(service.getActivePart());
085: }
086:
087: /**
088: * Creates a new find/replace dialog accessor anchored at the given shell.
089: *
090: * @param shell the shell if no site is used
091: * @since 3.3
092: */
093: public FindReplaceDialogStub(Shell shell) {
094: fDialog = new FindReplaceDialog(shell);
095: fDialog.create();
096: fDialog.getShell().addDisposeListener(this );
097: }
098:
099: /**
100: * Returns the find/replace dialog.
101: * @return the find/replace dialog
102: */
103: public FindReplaceDialog getDialog() {
104: return fDialog;
105: }
106:
107: /*
108: * @see IPartListener#partActivated(IWorkbenchPart)
109: */
110: public void partActivated(IWorkbenchPart part) {
111:
112: IFindReplaceTarget target = part == null ? null
113: : (IFindReplaceTarget) part
114: .getAdapter(IFindReplaceTarget.class);
115: fPreviousPart = fPart;
116: fPart = target == null ? null : part;
117:
118: if (fPreviousTarget != target) {
119: fPreviousTarget = target;
120: if (fDialog != null) {
121: boolean isEditable = false;
122: if (fPart instanceof ITextEditorExtension2) {
123: ITextEditorExtension2 extension = (ITextEditorExtension2) fPart;
124: isEditable = extension
125: .isEditorInputModifiable();
126: } else if (target != null)
127: isEditable = target.isEditable();
128: fDialog.updateTarget(target, isEditable, false);
129: }
130: }
131: }
132:
133: /*
134: * @see IPartListener#partClosed(IWorkbenchPart)
135: */
136: public void partClosed(IWorkbenchPart part) {
137:
138: if (part == fPreviousPart) {
139: fPreviousPart = null;
140: fPreviousTarget = null;
141: }
142:
143: if (part == fPart)
144: partActivated(null);
145: }
146:
147: /*
148: * @see DisposeListener#widgetDisposed(DisposeEvent)
149: */
150: public void widgetDisposed(DisposeEvent event) {
151:
152: if (fgFindReplaceDialogStub == this )
153: fgFindReplaceDialogStub = null;
154:
155: if (fgFindReplaceDialogStubShell == this )
156: fgFindReplaceDialogStubShell = null;
157:
158: if (fWindow != null) {
159: fWindow.getPartService().removePartListener(this );
160: fWindow = null;
161: }
162: fDialog = null;
163: fPart = null;
164: fPreviousPart = null;
165: fPreviousTarget = null;
166: }
167:
168: /*
169: * @see IPartListener#partOpened(IWorkbenchPart)
170: */
171: public void partOpened(IWorkbenchPart part) {
172: }
173:
174: /*
175: * @see IPartListener#partDeactivated(IWorkbenchPart)
176: */
177: public void partDeactivated(IWorkbenchPart part) {
178: }
179:
180: /*
181: * @see IPartListener#partBroughtToTop(IWorkbenchPart)
182: */
183: public void partBroughtToTop(IWorkbenchPart part) {
184: }
185:
186: /**
187: * Checks if the dialogs shell is the same as the
188: * given <code>shell</code> and if not clears the stub
189: * and closes the dialog.
190: *
191: * @param shell the shell check
192: * @since 3.3
193: */
194: public void checkShell(Shell shell) {
195: if (fDialog != null && shell != fDialog.getParentShell()) {
196: if (fgFindReplaceDialogStub == this )
197: fgFindReplaceDialogStub = null;
198:
199: if (fgFindReplaceDialogStubShell == this )
200: fgFindReplaceDialogStubShell = null;
201:
202: fDialog.close();
203: }
204: }
205: }
206:
207: /**
208: * Listener for disabling the dialog on shell close.
209: * <p>
210: * This stub is shared amongst <code>IWorkbenchPart</code>s.</p>
211: */
212: private static FindReplaceDialogStub fgFindReplaceDialogStub;
213:
214: /** Listener for disabling the dialog on shell close.
215: * <p>
216: * This stub is shared amongst <code>Shell</code>s.</p>
217: * @since 3.3
218: */
219: private static FindReplaceDialogStub fgFindReplaceDialogStubShell;
220:
221: /** The action's target */
222: private IFindReplaceTarget fTarget;
223: /** The part to use if the action is created with a part. */
224: private IWorkbenchPart fWorkbenchPart;
225: /** The workbench window */
226: private IWorkbenchWindow fWorkbenchWindow;
227: /**
228: * The shell to use if the action is created with a shell.
229: * @since 3.3
230: */
231: private Shell fShell;
232:
233: /**
234: * Creates a new find/replace action for the given workbench part.
235: * <p>
236: * The action configures its visual representation from the given
237: * resource bundle.</p>
238: *
239: * @param bundle the resource bundle
240: * @param prefix a prefix to be prepended to the various resource keys
241: * (described in <code>ResourceAction</code> constructor), or
242: * <code>null</code> if none
243: * @param workbenchPart the workbench part
244: * @see ResourceAction#ResourceAction(ResourceBundle, String)
245: */
246: public FindReplaceAction(ResourceBundle bundle, String prefix,
247: IWorkbenchPart workbenchPart) {
248: super (bundle, prefix);
249: Assert.isLegal(workbenchPart != null);
250: fWorkbenchPart = workbenchPart;
251: update();
252: }
253:
254: /**
255: * Creates a new find/replace action for the given target and shell.
256: * <p>
257: * This can be used without having an IWorkbenchPart e.g. for
258: * dialogs or wizards.</p>
259: * <p>
260: * The action configures its visual representation from the given
261: * resource bundle.</p>
262: *
263: * @param bundle the resource bundle
264: * @param prefix a prefix to be prepended to the various resource keys
265: * (described in <code>ResourceAction</code> constructor), or
266: * <code>null</code> if none
267: * @param target the IFindReplaceTarget to use
268: * @param shell the shell
269: * @see ResourceAction#ResourceAction(ResourceBundle, String)
270: *
271: * @since 3.3
272: */
273: public FindReplaceAction(ResourceBundle bundle, String prefix,
274: Shell shell, IFindReplaceTarget target) {
275: super (bundle, prefix);
276: Assert.isLegal(target != null && shell != null);
277: fTarget = target;
278: fShell = shell;
279: update();
280: }
281:
282: /**
283: * Creates a new find/replace action for the given workbench window.
284: * The action configures its visual representation from the given
285: * resource bundle.
286: *
287: * @param bundle the resource bundle
288: * @param prefix a prefix to be prepended to the various resource keys
289: * (described in <code>ResourceAction</code> constructor), or
290: * <code>null</code> if none
291: * @param workbenchWindow the workbench window
292: * @see ResourceAction#ResourceAction(ResourceBundle, String)
293: *
294: * @deprecated use FindReplaceAction(ResourceBundle, String, IWorkbenchPart) instead
295: */
296: public FindReplaceAction(ResourceBundle bundle, String prefix,
297: IWorkbenchWindow workbenchWindow) {
298: super (bundle, prefix);
299: fWorkbenchWindow = workbenchWindow;
300: update();
301: }
302:
303: /*
304: * @see IAction#run()
305: */
306: public void run() {
307: if (fTarget == null)
308: return;
309:
310: final FindReplaceDialog dialog;
311: final boolean isEditable;
312:
313: if (fShell == null) {
314: if (fgFindReplaceDialogStub != null) {
315: Shell shell = fWorkbenchPart.getSite().getShell();
316: fgFindReplaceDialogStub.checkShell(shell);
317: }
318: if (fgFindReplaceDialogStub == null)
319: fgFindReplaceDialogStub = new FindReplaceDialogStub(
320: fWorkbenchPart.getSite());
321:
322: if (fWorkbenchPart instanceof ITextEditorExtension2)
323: isEditable = ((ITextEditorExtension2) fWorkbenchPart)
324: .isEditorInputModifiable();
325: else
326: isEditable = fTarget.isEditable();
327:
328: dialog = fgFindReplaceDialogStub.getDialog();
329:
330: } else {
331: if (fgFindReplaceDialogStubShell != null) {
332: fgFindReplaceDialogStubShell.checkShell(fShell);
333: }
334: if (fgFindReplaceDialogStubShell == null)
335: fgFindReplaceDialogStubShell = new FindReplaceDialogStub(
336: fShell);
337:
338: isEditable = fTarget.isEditable();
339: dialog = fgFindReplaceDialogStubShell.getDialog();
340: }
341:
342: dialog.updateTarget(fTarget, isEditable, true);
343: dialog.open();
344: }
345:
346: /*
347: * @see IUpdate#update()
348: */
349: public void update() {
350:
351: if (fShell == null) {
352: if (fWorkbenchPart == null && fWorkbenchWindow != null)
353: fWorkbenchPart = fWorkbenchWindow.getPartService()
354: .getActivePart();
355:
356: if (fWorkbenchPart != null)
357: fTarget = (IFindReplaceTarget) fWorkbenchPart
358: .getAdapter(IFindReplaceTarget.class);
359: else
360: fTarget = null;
361: }
362: setEnabled(fTarget != null && fTarget.canPerformFind());
363: }
364: }
|