Line 0
Link Here
|
|
|
1 |
/* |
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
3 |
* |
4 |
* Copyright 2012 Oracle and/or its affiliates. All rights reserved. |
5 |
* |
6 |
* Oracle and Java are registered trademarks of Oracle and/or its affiliates. |
7 |
* Other names may be trademarks of their respective owners. |
8 |
* |
9 |
* The contents of this file are subject to the terms of either the GNU |
10 |
* General Public License Version 2 only ("GPL") or the Common |
11 |
* Development and Distribution License("CDDL") (collectively, the |
12 |
* "License"). You may not use this file except in compliance with the |
13 |
* License. You can obtain a copy of the License at |
14 |
* http://www.netbeans.org/cddl-gplv2.html |
15 |
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the |
16 |
* specific language governing permissions and limitations under the |
17 |
* License. When distributing the software, include this License Header |
18 |
* Notice in each file and include the License file at |
19 |
* nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this |
20 |
* particular file as subject to the "Classpath" exception as provided |
21 |
* by Oracle in the GPL Version 2 section of the License file that |
22 |
* accompanied this code. If applicable, add the following below the |
23 |
* License Header, with the fields enclosed by brackets [] replaced by |
24 |
* your own identifying information: |
25 |
* "Portions Copyrighted [year] [name of copyright owner]" |
26 |
* |
27 |
* If you wish your version of this file to be governed by only the CDDL |
28 |
* or only the GPL Version 2, indicate your decision by adding |
29 |
* "[Contributor] elects to include this software in this distribution |
30 |
* under the [CDDL or GPL Version 2] license." If you do not indicate a |
31 |
* single choice of license, a recipient has the option to distribute |
32 |
* your version of this file under either the CDDL, the GPL Version 2 or |
33 |
* to extend the choice of license to its licensees as provided above. |
34 |
* However, if you add GPL Version 2 code and therefore, elected the GPL |
35 |
* Version 2 license, then the option applies only if the new code is |
36 |
* made subject to such option by the copyright holder. |
37 |
* |
38 |
* Contributor(s): |
39 |
* |
40 |
* Portions Copyrighted 2012 Sun Microsystems, Inc. |
41 |
*/ |
42 |
package org.netbeans.modules.refactoring.spi.ui; |
43 |
|
44 |
import java.awt.Component; |
45 |
import java.awt.event.ActionEvent; |
46 |
import java.util.ArrayList; |
47 |
import java.util.Collection; |
48 |
import java.util.Collections; |
49 |
import java.util.Comparator; |
50 |
import java.util.List; |
51 |
import java.util.concurrent.atomic.AtomicBoolean; |
52 |
import java.util.prefs.Preferences; |
53 |
import javax.swing.AbstractAction; |
54 |
import javax.swing.ComboBoxModel; |
55 |
import javax.swing.DefaultComboBoxModel; |
56 |
import javax.swing.JComboBox; |
57 |
import javax.swing.JLabel; |
58 |
import javax.swing.JList; |
59 |
import javax.swing.ListCellRenderer; |
60 |
import javax.swing.SwingUtilities; |
61 |
import javax.swing.plaf.UIResource; |
62 |
import org.netbeans.api.annotations.common.CheckForNull; |
63 |
import org.netbeans.api.annotations.common.NonNull; |
64 |
import org.netbeans.modules.refactoring.api.Scope; |
65 |
import org.netbeans.modules.refactoring.spi.impl.DelegatingCustomScopeProvider; |
66 |
import org.netbeans.modules.refactoring.spi.impl.DelegatingScopeInformation; |
67 |
import org.openide.util.Lookup; |
68 |
import org.openide.util.lookup.Lookups; |
69 |
|
70 |
/** |
71 |
* ScopePanel provides a component to use for scope selection. A customize |
72 |
* button (a JButton with ellipses) will be displayed when any of the registered |
73 |
* scopes is customizable. |
74 |
* |
75 |
* @author Ralph Benjamin Ruijs <ralphbenjamin@netbeans.org> |
76 |
* @since 1.30 |
77 |
*/ |
78 |
public final class ScopePanel extends javax.swing.JPanel { |
79 |
|
80 |
private static final String ELLIPSIS = "\u2026"; //NOI18N |
81 |
private static final int SCOPE_COMBOBOX_COLUMNS = 14; |
82 |
private final String id; |
83 |
private final Preferences preferences; |
84 |
private final String preferencesKey; |
85 |
private ArrayList<DelegatingScopeInformation> scopes; |
86 |
|
87 |
/** |
88 |
* Creates new form ScopePanel. |
89 |
* |
90 |
* @deprecated do not use this constructor. Only available for the Matisse |
91 |
* GUI-builder. |
92 |
*/ |
93 |
@Deprecated |
94 |
public ScopePanel() { |
95 |
this(null, null, null); |
96 |
} |
97 |
|
98 |
/** |
99 |
* Creates a new ScopePanel. The supplied id will be used to only get the |
100 |
* Scopes registered for a specific set of Scopes. The preferences and |
101 |
* preferencesKey will be used to store the user's selection. |
102 |
* |
103 |
* @param id the id for which the scopes are registered |
104 |
* @param preferences a preferences object to store user's selection |
105 |
* @param preferencesKey a key to use to store user's selection |
106 |
*/ |
107 |
public ScopePanel(String id, Preferences preferences, String preferencesKey) { |
108 |
this.id = id; |
109 |
this.preferences = preferences; |
110 |
this.preferencesKey = preferencesKey; |
111 |
this.scopes = new ArrayList<DelegatingScopeInformation>(); |
112 |
initComponents(); |
113 |
} |
114 |
|
115 |
/** |
116 |
* Initializes the Combobox and customize button of this ScopePanel. The |
117 |
* context will be passed to the different ScopeProviders initialize method. |
118 |
* This method will return false if there are no available scopes and this |
119 |
* panel should not be available to the user. |
120 |
* |
121 |
* @param context the Lookup to pass to the ScopeProviders |
122 |
* @return true if there is at least one Scope available, false otherwise |
123 |
*/ |
124 |
public boolean initialize(Lookup context, AtomicBoolean cancel) { |
125 |
scopes.clear(); |
126 |
Collection<? extends ScopeProvider> scopeProviders = Lookups.forPath("Scopes" + "/" + id).lookupAll(ScopeProvider.class); |
127 |
final AtomicBoolean customizable = new AtomicBoolean(); |
128 |
for (ScopeProvider provider : scopeProviders) { |
129 |
if (provider.initialize(context, new AtomicBoolean())) { |
130 |
scopes.add((DelegatingScopeInformation)provider); |
131 |
if (provider instanceof ScopeProvider.CustomScopeProvider) { |
132 |
customizable.set(true); |
133 |
} |
134 |
} |
135 |
} |
136 |
|
137 |
Collections.sort(scopes, new Comparator<DelegatingScopeInformation>() { |
138 |
@Override |
139 |
public int compare(DelegatingScopeInformation o1, DelegatingScopeInformation o2) { |
140 |
return (o1.getPosition() < o2.getPosition() ? -1 : (o1.getPosition() == o2.getPosition() ? 0 : 1)); |
141 |
} |
142 |
}); |
143 |
if (!scopes.isEmpty()) { |
144 |
SwingUtilities.invokeLater(new Runnable() { |
145 |
@Override |
146 |
public void run() { |
147 |
scopeCombobox.setModel(new DefaultComboBoxModel(scopes.toArray(new ScopeProvider[scopes.size()]))); |
148 |
for (DelegatingScopeInformation scopeProvider : scopes) { |
149 |
if(scopeProvider instanceof ScopeProvider.CustomScopeProvider) { |
150 |
ScopePanel.this.btnCustomScope.setVisible(false); |
151 |
break; |
152 |
} |
153 |
} |
154 |
String preselectId = preferences.get(preferencesKey, null); |
155 |
if (preselectId == null) { // Needed for the old preferences of Java's Where Used Panel. |
156 |
int defaultItem = (Integer) preferences.getInt(preferencesKey, -1); // NOI18N |
157 |
if (defaultItem != (-1)) { |
158 |
switch (defaultItem) { |
159 |
case 0: |
160 |
preselectId = "all-projects"; |
161 |
break; |
162 |
case 1: |
163 |
preselectId = "current-project"; |
164 |
break; |
165 |
case 2: |
166 |
preselectId = "current-package"; |
167 |
break; |
168 |
case 3: |
169 |
preselectId = "current-file"; |
170 |
break; |
171 |
case 4: |
172 |
preselectId = "custom-scope"; |
173 |
break; |
174 |
} |
175 |
} |
176 |
} |
177 |
if (preselectId != null) { |
178 |
selectScopeById(preselectId); |
179 |
} else { |
180 |
selectPreferredScope(); |
181 |
} |
182 |
} |
183 |
}); |
184 |
} |
185 |
return !scopes.isEmpty(); |
186 |
} |
187 |
|
188 |
/** |
189 |
* The currently selected scope in the Combobox. This can be a predefined |
190 |
* scope, or a customized one. |
191 |
* |
192 |
* @return the selected Scope |
193 |
*/ |
194 |
@CheckForNull |
195 |
public Scope getSelectedScope() { |
196 |
return ((ScopeProvider) scopeCombobox.getSelectedItem()).getScope(); |
197 |
} |
198 |
|
199 |
/** |
200 |
* Change the selected scope to one with the specified id. If the id does |
201 |
* not exist, nothing is changed. When the id is from a CustomScopeProvider |
202 |
* and it returns an empty scope, the preferred scope is selected. |
203 |
* |
204 |
* @see ScopeProvider.CustomScopeProvider |
205 |
* |
206 |
* @param id the id of the scope to select |
207 |
*/ |
208 |
public void selectScopeById(@NonNull String id) { |
209 |
ComboBoxModel m = scopeCombobox.getModel(); |
210 |
|
211 |
for (int i = 0; i < m.getSize(); i++) { |
212 |
DelegatingScopeInformation sd = (DelegatingScopeInformation) m.getElementAt(i); |
213 |
|
214 |
if (sd.getId().equals(id)) { |
215 |
if (sd instanceof ScopeProvider.CustomScopeProvider) { |
216 |
Scope s = sd.getScope(); |
217 |
if (s != null |
218 |
&& s.getFiles().isEmpty() |
219 |
&& s.getFolders().isEmpty() |
220 |
&& s.getSourceRoots().isEmpty()) { |
221 |
selectPreferredScope(); |
222 |
return; |
223 |
} |
224 |
} |
225 |
scopeCombobox.setSelectedItem(sd); |
226 |
return; |
227 |
} |
228 |
} |
229 |
} |
230 |
|
231 |
/** |
232 |
* This method is called from within the constructor to initialize the form. |
233 |
* WARNING: Do NOT modify this code. The content of this method is always |
234 |
* regenerated by the Form Editor. |
235 |
*/ |
236 |
@SuppressWarnings("unchecked") |
237 |
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents |
238 |
private void initComponents() { |
239 |
|
240 |
btnCustomScope = new javax.swing.JButton(); |
241 |
scopeCombobox = new javax.swing.JComboBox(); |
242 |
|
243 |
btnCustomScope.setAction(new ScopeAction(scopeCombobox)); |
244 |
org.openide.awt.Mnemonics.setLocalizedText(btnCustomScope, "..."); // NOI18N |
245 |
|
246 |
scopeCombobox.setRenderer(new ScopeDescriptionRenderer()); |
247 |
((javax.swing.JTextField) scopeCombobox.getEditor().getEditorComponent()).setColumns(SCOPE_COMBOBOX_COLUMNS); |
248 |
scopeCombobox.addActionListener(new java.awt.event.ActionListener() { |
249 |
public void actionPerformed(java.awt.event.ActionEvent evt) { |
250 |
scopeComboboxActionPerformed(evt); |
251 |
} |
252 |
}); |
253 |
|
254 |
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); |
255 |
this.setLayout(layout); |
256 |
layout.setHorizontalGroup( |
257 |
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
258 |
.addGroup(layout.createSequentialGroup() |
259 |
.addComponent(scopeCombobox, 0, 343, Short.MAX_VALUE) |
260 |
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) |
261 |
.addComponent(btnCustomScope)) |
262 |
); |
263 |
layout.setVerticalGroup( |
264 |
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
265 |
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) |
266 |
.addComponent(btnCustomScope) |
267 |
.addComponent(scopeCombobox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) |
268 |
); |
269 |
}// </editor-fold>//GEN-END:initComponents |
270 |
|
271 |
private void scopeComboboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scopeComboboxActionPerformed |
272 |
preferences.putInt(preferencesKey, scopeCombobox.getSelectedIndex()); |
273 |
}//GEN-LAST:event_scopeComboboxActionPerformed |
274 |
// Variables declaration - do not modify//GEN-BEGIN:variables |
275 |
private javax.swing.JButton btnCustomScope; |
276 |
private javax.swing.JComboBox scopeCombobox; |
277 |
// End of variables declaration//GEN-END:variables |
278 |
|
279 |
private void selectPreferredScope() { |
280 |
ComboBoxModel m = scopeCombobox.getModel(); |
281 |
|
282 |
for (int i = 0; i < m.getSize(); i++) { |
283 |
DelegatingScopeInformation sd = (DelegatingScopeInformation) m.getElementAt(i); |
284 |
|
285 |
if (sd.getPosition() >= 0) { |
286 |
scopeCombobox.setSelectedItem(sd); |
287 |
return; |
288 |
} |
289 |
} |
290 |
} |
291 |
|
292 |
private class ScopeAction extends AbstractAction { |
293 |
|
294 |
private final JComboBox scopeCombobox; |
295 |
|
296 |
private ScopeAction(JComboBox scopeCombobox) { |
297 |
this.scopeCombobox = scopeCombobox; |
298 |
this.putValue(NAME, ELLIPSIS); |
299 |
} |
300 |
|
301 |
@Override |
302 |
public void actionPerformed(ActionEvent e) { |
303 |
ComboBoxModel m = this.scopeCombobox.getModel(); |
304 |
ScopeProvider selectedScope = (ScopeProvider) scopeCombobox.getSelectedItem(); |
305 |
Scope scope = selectedScope.getScope(); |
306 |
if (selectedScope instanceof DelegatingCustomScopeProvider) { |
307 |
showCustomizer((DelegatingCustomScopeProvider) selectedScope, scope); |
308 |
} else { |
309 |
for (int i = 0; i < m.getSize(); i++) { |
310 |
ScopeProvider sd = (ScopeProvider) m.getElementAt(i); |
311 |
|
312 |
if (sd instanceof DelegatingCustomScopeProvider) { |
313 |
showCustomizer((DelegatingCustomScopeProvider) sd, scope); |
314 |
break; |
315 |
} |
316 |
} |
317 |
} |
318 |
} |
319 |
|
320 |
private void showCustomizer(DelegatingCustomScopeProvider csd, Scope scope) { |
321 |
csd.setScope(scope); |
322 |
if (csd.showCustomizer()) { |
323 |
selectScopeById(csd.getId()); |
324 |
} |
325 |
} |
326 |
} |
327 |
|
328 |
private static class ScopeDescriptionRenderer extends JLabel implements ListCellRenderer, UIResource { |
329 |
|
330 |
public ScopeDescriptionRenderer() { |
331 |
setOpaque(true); |
332 |
} |
333 |
|
334 |
@Override |
335 |
public Component getListCellRendererComponent( |
336 |
JList list, |
337 |
Object value, |
338 |
int index, |
339 |
boolean isSelected, |
340 |
boolean cellHasFocus) { |
341 |
|
342 |
// #89393: GTK needs name to render cell renderer "natively" |
343 |
setName("ComboBox.listRenderer"); // NOI18N |
344 |
DelegatingScopeInformation scopeDescription = null; |
345 |
if (value instanceof DelegatingScopeInformation) { |
346 |
scopeDescription = (DelegatingScopeInformation) value; |
347 |
} |
348 |
if (scopeDescription != null) { |
349 |
String detail = scopeDescription.getDetail(); |
350 |
String displayName = scopeDescription.getDisplayName(); |
351 |
setText(detail == null ? displayName : displayName + " (" + detail + ")"); |
352 |
setIcon(scopeDescription.getIcon()); |
353 |
} |
354 |
|
355 |
if (isSelected) { |
356 |
setBackground(list.getSelectionBackground()); |
357 |
setForeground(list.getSelectionForeground()); |
358 |
} else { |
359 |
setBackground(list.getBackground()); |
360 |
setForeground(list.getForeground()); |
361 |
} |
362 |
|
363 |
return this; |
364 |
} |
365 |
|
366 |
// #89393: GTK needs name to render cell renderer "natively" |
367 |
@Override |
368 |
public String getName() { |
369 |
String name = super.getName(); |
370 |
return name == null ? "ComboBox.renderer" : name; // NOI18N |
371 |
} |
372 |
} |
373 |
} |