KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > texteditor > CompoundEditExitStrategy


1 /*******************************************************************************
2  * Copyright (c) 2005, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.internal.texteditor;
12
13
14 import org.eclipse.swt.SWT;
15 import org.eclipse.swt.custom.StyledText;
16 import org.eclipse.swt.custom.VerifyKeyListener;
17 import org.eclipse.swt.events.FocusEvent;
18 import org.eclipse.swt.events.FocusListener;
19 import org.eclipse.swt.events.MouseEvent;
20 import org.eclipse.swt.events.MouseListener;
21 import org.eclipse.swt.events.VerifyEvent;
22
23 import org.eclipse.core.commands.ExecutionEvent;
24 import org.eclipse.core.commands.ExecutionException;
25 import org.eclipse.core.commands.IExecutionListener;
26 import org.eclipse.core.commands.NotHandledException;
27
28 import org.eclipse.core.runtime.IStatus;
29 import org.eclipse.core.runtime.ListenerList;
30 import org.eclipse.core.runtime.Status;
31
32 import org.eclipse.jface.text.ITextViewer;
33
34 import org.eclipse.ui.PlatformUI;
35 import org.eclipse.ui.commands.ICommandService;
36
37 /**
38  * Exit strategy for commands that want to fold repeated execution into one compound edit. See
39  * {@link org.eclipse.jface.text.IRewriteTarget#endCompoundChange() IRewriteTarget.endCompoundChange}.
40  * As long as a strategy is installed on an {@link ITextViewer}, it will detect the end of a
41  * compound operation when any of the following conditions becomes true:
42  * <ul>
43  * <li>the viewer's text widget loses the keyboard focus</li>
44  * <li>the mouse is clicked or double clicked inside the viewer's widget</li>
45  * <li>a command other than the ones specified is executed</li>
46  * <li>the viewer receives any key events that are not modifier combinations</li>
47  * </ul>
48  * <p>
49  * If the end of a compound edit is detected, any registered {@link ICompoundEditListener}s are
50  * notified and the strategy is disarmed (spring-loaded).
51  * </p>
52  *
53  * @since 3.1
54  */

55 public final class CompoundEditExitStrategy {
56     /**
57      * Listens for events that may trigger the end of a compound edit.
58      */

59     private final class EventListener implements MouseListener, FocusListener, VerifyKeyListener, IExecutionListener {
60
61         /*
62          * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
63          */

64         public void mouseDoubleClick(MouseEvent e) {
65             // mouse actions end the compound change
66
fireEndCompoundEdit();
67         }
68
69         /*
70          * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
71          */

72         public void mouseDown(MouseEvent e) {
73             // mouse actions end the compound change
74
fireEndCompoundEdit();
75         }
76
77         public void mouseUp(MouseEvent e) {}
78
79         public void focusGained(FocusEvent e) {}
80
81         /*
82          * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent)
83          */

84         public void focusLost(FocusEvent e) {
85             // losing focus ends the change
86
fireEndCompoundEdit();
87         }
88
89         public void notHandled(String JavaDoc commandId, NotHandledException exception) {}
90
91         public void postExecuteFailure(String JavaDoc commandId, ExecutionException exception) {}
92
93         public void postExecuteSuccess(String JavaDoc commandId, Object JavaDoc returnValue) {}
94
95         /*
96          * @see org.eclipse.core.commands.IExecutionListener#preExecute(java.lang.String, org.eclipse.core.commands.ExecutionEvent)
97          */

98         public void preExecute(String JavaDoc commandId, ExecutionEvent event) {
99             // any command other than the known ones end the compound change
100
for (int i= 0; i < fCommandIds.length; i++) {
101                 if (commandId.equals(fCommandIds[i]))
102                     return;
103             }
104             fireEndCompoundEdit();
105         }
106
107         /*
108          * @see org.eclipse.swt.custom.VerifyKeyListener#verifyKey(org.eclipse.swt.events.VerifyEvent)
109          */

110         public void verifyKey(VerifyEvent event) {
111             // any key press that is not a modifier combo ends the compound change
112
final int maskWithoutShift= SWT.MODIFIER_MASK & ~SWT.SHIFT;
113             if ((event.keyCode & SWT.MODIFIER_MASK) == 0 && (event.stateMask & maskWithoutShift) == 0)
114                 fireEndCompoundEdit();
115         }
116         
117     }
118
119     private final String JavaDoc[] fCommandIds;
120     private final EventListener fEventListener= new EventListener();
121     private final ListenerList fListenerList= new ListenerList(ListenerList.IDENTITY);
122
123     private ITextViewer fViewer;
124     private StyledText fWidgetEventSource;
125
126     /**
127      * Creates a new strategy, equivalent to calling
128      * {@linkplain #CompoundEditExitStrategy(String[]) CompoundEditExitStrategy(new String[] &#x7b; commandId &#x7d;)}.
129      *
130      * @param commandId the command id of the repeatable command
131      */

132     public CompoundEditExitStrategy(String JavaDoc commandId) {
133         if (commandId == null)
134             throw new NullPointerException JavaDoc("commandId"); //$NON-NLS-1$
135
fCommandIds= new String JavaDoc[] {commandId};
136     }
137     
138     /**
139      * Creates a new strategy, ending upon execution of any command other than the ones
140      * specified.
141      *
142      * @param commandIds the ids of the repeatable commands
143      */

144     public CompoundEditExitStrategy(String JavaDoc[] commandIds) {
145         for (int i= 0; i < commandIds.length; i++) {
146             if (commandIds[i] == null)
147                 throw new NullPointerException JavaDoc("commandIds[" + i + "]"); //$NON-NLS-1$ //$NON-NLS-2$
148
}
149         fCommandIds= new String JavaDoc[commandIds.length];
150         System.arraycopy(commandIds, 0, fCommandIds, 0, commandIds.length);
151     }
152     
153     /**
154      * Installs the receiver on <code>viewer</code> and arms it. After this call returns, any
155      * registered listeners will be notified if a compound edit ends.
156      *
157      * @param viewer the viewer to install on
158      */

159     public void arm(ITextViewer viewer) {
160         disarm();
161         if (viewer == null)
162             throw new NullPointerException JavaDoc("editor"); //$NON-NLS-1$
163
fViewer= viewer;
164         addListeners(fViewer);
165     }
166     
167     /**
168      * Disarms the receiver. After this call returns, any registered listeners will be not be
169      * notified any more until <code>install</code> is called again. Note that the listeners are
170      * not removed.
171      * <p>
172      * Note that the receiver is automatically disarmed when the end of a compound edit has
173      * been detected and before the listeners are notified.
174      * </p>
175      */

176     public void disarm() {
177         if (isInstalled()) {
178             removeListeners(fViewer);
179             fViewer= null;
180         }
181     }
182
183     private void addListeners(ITextViewer viewer) {
184         fWidgetEventSource= viewer.getTextWidget();
185         if (fWidgetEventSource != null) {
186             fWidgetEventSource.addVerifyKeyListener(fEventListener);
187             fWidgetEventSource.addMouseListener(fEventListener);
188             fWidgetEventSource.addFocusListener(fEventListener);
189         }
190
191         ICommandService commandService= (ICommandService)PlatformUI.getWorkbench().getAdapter(ICommandService.class);
192         if (commandService != null)
193             commandService.addExecutionListener(fEventListener);
194     }
195     
196     private void removeListeners(ITextViewer editor) {
197         ICommandService commandService= (ICommandService)PlatformUI.getWorkbench().getAdapter(ICommandService.class);
198         if (commandService != null)
199             commandService.removeExecutionListener(fEventListener);
200         
201         if (fWidgetEventSource != null) {
202             fWidgetEventSource.removeFocusListener(fEventListener);
203             fWidgetEventSource.removeMouseListener(fEventListener);
204             fWidgetEventSource.removeVerifyKeyListener(fEventListener);
205             fWidgetEventSource= null;
206         }
207     }
208
209     private boolean isInstalled() {
210         return fViewer != null;
211     }
212     
213     private void fireEndCompoundEdit() {
214         disarm();
215         Object JavaDoc[] listeners= fListenerList.getListeners();
216         for (int i= 0; i < listeners.length; i++) {
217             ICompoundEditListener listener= (ICompoundEditListener) listeners[i];
218             try {
219                 listener.endCompoundEdit();
220             } catch (Exception JavaDoc e) {
221                 IStatus status= new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, IStatus.OK, "listener notification failed", e); //$NON-NLS-1$
222
TextEditorPlugin.getDefault().getLog().log(status);
223             }
224         }
225     }
226     
227     /**
228      * Adds a compound edit listener. Multiple registration is possible. Note that the receiver is
229      * automatically disarmed before the listeners are notified.
230      *
231      * @param listener the new listener
232      */

233     public void addCompoundListener(ICompoundEditListener listener) {
234         fListenerList.add(listener);
235     }
236     
237     /**
238      * Removes a compound edit listener. If <code>listener</code> is registered multiple times, an
239      * arbitrary instance is removed. If <code>listener</code> is not currently registered,
240      * nothing happens.
241      *
242      * @param listener the listener to be removed.
243      */

244     public void removeCompoundListener(ICompoundEditListener listener) {
245         fListenerList.remove(listener);
246     }
247     
248 }
249
Popular Tags