1f0ebc208682390f3047e4588fb0a18a77bf6a18
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / text / template / contentassist / MultiVariableGuess.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.text.template.contentassist;
12
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
16
17 import org.eclipse.jface.text.Assert;
18 import org.eclipse.jface.text.BadLocationException;
19 import org.eclipse.jface.text.DocumentEvent;
20 import org.eclipse.jface.text.IDocument;
21 import org.eclipse.jface.text.ITextViewer;
22 import org.eclipse.jface.text.contentassist.ICompletionProposal;
23 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2;
24 import org.eclipse.jface.text.contentassist.IContextInformation;
25 import org.eclipse.swt.graphics.Image;
26 import org.eclipse.swt.graphics.Point;
27
28 /**
29  * Global state for templates. Selecting a proposal for the master template
30  * variable will cause the value (and the proposals) for the slave variables to
31  * change.
32  * 
33  * @see MultiVariable
34  */
35 public class MultiVariableGuess {
36
37         /**
38          * Implementation of the <code>ICompletionProposal</code> interface and
39          * extension.
40          */
41         class Proposal implements ICompletionProposal,
42                         ICompletionProposalExtension2 {
43
44                 /** The string to be displayed in the completion proposal popup */
45                 private String fDisplayString;
46
47                 /** The replacement string */
48                 String fReplacementString;
49
50                 /** The replacement offset */
51                 private int fReplacementOffset;
52
53                 /** The replacement length */
54                 private int fReplacementLength;
55
56                 /** The cursor position after this proposal has been applied */
57                 private int fCursorPosition;
58
59                 /** The image to be displayed in the completion proposal popup */
60                 private Image fImage;
61
62                 /** The context information of this proposal */
63                 private IContextInformation fContextInformation;
64
65                 /** The additional info of this proposal */
66                 private String fAdditionalProposalInfo;
67
68                 /**
69                  * Creates a new completion proposal based on the provided information.
70                  * The replacement string is considered being the display string too.
71                  * All remaining fields are set to <code>null</code>.
72                  * 
73                  * @param replacementString
74                  *            the actual string to be inserted into the document
75                  * @param replacementOffset
76                  *            the offset of the text to be replaced
77                  * @param replacementLength
78                  *            the length of the text to be replaced
79                  * @param cursorPosition
80                  *            the position of the cursor following the insert relative
81                  *            to replacementOffset
82                  */
83                 public Proposal(String replacementString, int replacementOffset,
84                                 int replacementLength, int cursorPosition) {
85                         this(replacementString, replacementOffset, replacementLength,
86                                         cursorPosition, null, null, null, null);
87                 }
88
89                 /**
90                  * Creates a new completion proposal. All fields are initialized based
91                  * on the provided information.
92                  * 
93                  * @param replacementString
94                  *            the actual string to be inserted into the document
95                  * @param replacementOffset
96                  *            the offset of the text to be replaced
97                  * @param replacementLength
98                  *            the length of the text to be replaced
99                  * @param cursorPosition
100                  *            the position of the cursor following the insert relative
101                  *            to replacementOffset
102                  * @param image
103                  *            the image to display for this proposal
104                  * @param displayString
105                  *            the string to be displayed for the proposal
106                  * @param contextInformation
107                  *            the context information associated with this proposal
108                  * @param additionalProposalInfo
109                  *            the additional information associated with this proposal
110                  */
111                 public Proposal(String replacementString, int replacementOffset,
112                                 int replacementLength, int cursorPosition, Image image,
113                                 String displayString, IContextInformation contextInformation,
114                                 String additionalProposalInfo) {
115                         Assert.isNotNull(replacementString);
116                         Assert.isTrue(replacementOffset >= 0);
117                         Assert.isTrue(replacementLength >= 0);
118                         Assert.isTrue(cursorPosition >= 0);
119
120                         fReplacementString = replacementString;
121                         fReplacementOffset = replacementOffset;
122                         fReplacementLength = replacementLength;
123                         fCursorPosition = cursorPosition;
124                         fImage = image;
125                         fDisplayString = displayString;
126                         fContextInformation = contextInformation;
127                         fAdditionalProposalInfo = additionalProposalInfo;
128                 }
129
130                 /*
131                  * @see ICompletionProposal#apply(IDocument)
132                  */
133                 public void apply(IDocument document) {
134                         try {
135                                 document.replace(fReplacementOffset, fReplacementLength,
136                                                 fReplacementString);
137                         } catch (BadLocationException x) {
138                                 // ignore
139                         }
140                 }
141
142                 /*
143                  * @see ICompletionProposal#getSelection(IDocument)
144                  */
145                 public Point getSelection(IDocument document) {
146                         return new Point(fReplacementOffset + fCursorPosition, 0);
147                 }
148
149                 /*
150                  * @see ICompletionProposal#getContextInformation()
151                  */
152                 public IContextInformation getContextInformation() {
153                         return fContextInformation;
154                 }
155
156                 /*
157                  * @see ICompletionProposal#getImage()
158                  */
159                 public Image getImage() {
160                         return fImage;
161                 }
162
163                 /*
164                  * @see ICompletionProposal#getDisplayString()
165                  */
166                 public String getDisplayString() {
167                         if (fDisplayString != null)
168                                 return fDisplayString;
169                         return fReplacementString;
170                 }
171
172                 /*
173                  * @see ICompletionProposal#getAdditionalProposalInfo()
174                  */
175                 public String getAdditionalProposalInfo() {
176                         return fAdditionalProposalInfo;
177                 }
178
179                 /*
180                  * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#apply(org.eclipse.jface.text.ITextViewer,
181                  *      char, int, int)
182                  */
183                 public void apply(ITextViewer viewer, char trigger, int stateMask,
184                                 int offset) {
185                         apply(viewer.getDocument());
186                 }
187
188                 /*
189                  * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#selected(org.eclipse.jface.text.ITextViewer,
190                  *      boolean)
191                  */
192                 public void selected(ITextViewer viewer, boolean smartToggle) {
193                 }
194
195                 /*
196                  * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#unselected(org.eclipse.jface.text.ITextViewer)
197                  */
198                 public void unselected(ITextViewer viewer) {
199                 }
200
201                 /*
202                  * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#validate(org.eclipse.jface.text.IDocument,
203                  *      int, org.eclipse.jface.text.DocumentEvent)
204                  */
205                 public boolean validate(IDocument document, int offset,
206                                 DocumentEvent event) {
207                         try {
208                                 String content = document.get(fReplacementOffset,
209                                                 fReplacementLength);
210                                 if (content.startsWith(fReplacementString))
211                                         return true;
212                         } catch (BadLocationException e) {
213                                 // ignore concurrently modified document
214                         }
215                         return false;
216                 }
217         }
218
219         private final List fSlaves = new ArrayList();
220
221         private MultiVariable fMaster;
222
223         /**
224          * @param mv
225          */
226         public MultiVariableGuess(MultiVariable mv) {
227                 fMaster = mv;
228         }
229
230         /**
231          * @param variable
232          * @return
233          */
234         public ICompletionProposal[] getProposals(MultiVariable variable,
235                         int offset, int length) {
236                 if (variable.equals(fMaster)) {
237                         String[] choices = variable.getValues();
238
239                         ICompletionProposal[] ret = new ICompletionProposal[choices.length];
240                         for (int i = 0; i < ret.length; i++) {
241                                 ret[i] = new Proposal(choices[i], offset, length, offset
242                                                 + length) {
243
244                                         /*
245                                          * @see org.eclipse.jface.text.link.MultiVariableGuess.Proposal#apply(org.eclipse.jface.text.IDocument)
246                                          */
247                                         public void apply(IDocument document) {
248                                                 super.apply(document);
249
250                                                 try {
251                                                         Object old = fMaster.getSet();
252                                                         fMaster.setSet(fReplacementString);
253                                                         if (!fReplacementString.equals(old)) {
254                                                                 for (Iterator it = fSlaves.iterator(); it
255                                                                                 .hasNext();) {
256                                                                         VariablePosition pos = (VariablePosition) it
257                                                                                         .next();
258                                                                         String[] values = pos.getVariable()
259                                                                                         .getValues(fReplacementString);
260                                                                         if (values != null)
261                                                                                 document.replace(pos.getOffset(), pos
262                                                                                                 .getLength(), values[0]);
263                                                                 }
264                                                         }
265                                                 } catch (BadLocationException e) {
266                                                         // ignore and continue
267                                                 }
268
269                                         }
270                                 };
271                         }
272
273                         return ret;
274
275                 } else {
276
277                         String[] choices = variable.getValues(fMaster.getSet());
278
279                         if (choices == null || choices.length < 2)
280                                 return null;
281
282                         ICompletionProposal[] ret = new ICompletionProposal[choices.length];
283                         for (int i = 0; i < ret.length; i++) {
284                                 ret[i] = new Proposal(choices[i], offset, length, offset
285                                                 + length);
286                         }
287
288                         return ret;
289                 }
290         }
291
292         /**
293          * @param position
294          */
295         public void addSlave(VariablePosition position) {
296                 fSlaves.add(position);
297         }
298
299 }