Line 0
Link Here
|
|
|
1 |
/* |
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
3 |
* |
4 |
* Copyright 2013 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 2013 Sun Microsystems, Inc. |
41 |
*/ |
42 |
package org.netbeans.modules.java.project; |
43 |
|
44 |
import java.awt.Component; |
45 |
import java.awt.event.ActionEvent; |
46 |
import java.awt.event.ActionListener; |
47 |
import java.io.File; |
48 |
import java.net.MalformedURLException; |
49 |
import java.net.URI; |
50 |
import java.net.URISyntaxException; |
51 |
import java.net.URL; |
52 |
import java.util.ArrayList; |
53 |
import java.util.Collection; |
54 |
import java.util.Collections; |
55 |
import java.util.HashSet; |
56 |
import java.util.List; |
57 |
import java.util.Map; |
58 |
import java.util.Set; |
59 |
import java.util.regex.Matcher; |
60 |
import java.util.regex.Pattern; |
61 |
import javax.swing.AbstractListModel; |
62 |
import javax.swing.DefaultListCellRenderer; |
63 |
import javax.swing.JButton; |
64 |
import javax.swing.JList; |
65 |
import javax.swing.ListSelectionModel; |
66 |
import javax.swing.event.ListDataEvent; |
67 |
import javax.swing.event.ListDataListener; |
68 |
import javax.swing.event.ListSelectionEvent; |
69 |
import javax.swing.event.ListSelectionListener; |
70 |
import org.netbeans.api.annotations.common.CheckForNull; |
71 |
import org.netbeans.api.annotations.common.NonNull; |
72 |
import org.netbeans.api.annotations.common.NullAllowed; |
73 |
import org.openide.filesystems.FileUtil; |
74 |
import org.openide.util.NbBundle; |
75 |
import org.openide.util.Utilities; |
76 |
|
77 |
/** |
78 |
* |
79 |
* @author Tomas Zezula |
80 |
*/ |
81 |
public class FixProfile extends javax.swing.JPanel { |
82 |
|
83 |
private static final Pattern PROFILE_PATTERN = Pattern.compile("compact([123])"); //NOI18N |
84 |
private static final String PROFILE_FORMAT = "compact%d"; //NOI18N |
85 |
private static final int FULL_JRE = 4; |
86 |
|
87 |
private final JButton okOption; |
88 |
private final LibsModel libsModel; |
89 |
private String reqProfile; |
90 |
|
91 |
/** |
92 |
* Creates new form FixProfile |
93 |
*/ |
94 |
FixProfile( |
95 |
@NonNull final JButton okOption, |
96 |
@NonNull final String currentProfile, |
97 |
@NonNull final Map<String,Map<URI,String>> state) { |
98 |
assert okOption != null; |
99 |
assert currentProfile != null; |
100 |
assert state != null; |
101 |
this.okOption = okOption; |
102 |
this.libsModel = new LibsModel (currentProfile, state); |
103 |
libsModel.addListDataListener(new ListDataListener() { |
104 |
@Override |
105 |
public void intervalAdded(ListDataEvent lde) { |
106 |
checkOkOption(); |
107 |
} |
108 |
|
109 |
@Override |
110 |
public void intervalRemoved(ListDataEvent lde) { |
111 |
checkOkOption(); |
112 |
} |
113 |
|
114 |
@Override |
115 |
public void contentsChanged(ListDataEvent lde) { |
116 |
checkOkOption(); |
117 |
} |
118 |
}); |
119 |
this.reqProfile = requiredProfile(state); |
120 |
initComponents(); |
121 |
remove.setEnabled(false); |
122 |
brokenLibs.setModel(libsModel); |
123 |
brokenLibs.setCellRenderer(new LibsRenderer()); |
124 |
brokenLibs.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); |
125 |
brokenLibs.addListSelectionListener(new ListSelectionListener() { |
126 |
@Override |
127 |
public void valueChanged(ListSelectionEvent lse) { |
128 |
remove.setEnabled(brokenLibs.getSelectedIndex() != -1); |
129 |
} |
130 |
}); |
131 |
brokenLibs.setSelectedIndex(0); |
132 |
profiles.setRenderer(new ProfilesRenderer()); |
133 |
changeProfile.addActionListener(new ActionListener() { |
134 |
@Override |
135 |
public void actionPerformed(ActionEvent ae) { |
136 |
libsModel.updateProfile(changeProfile.isSelected()); |
137 |
checkOkOption(); |
138 |
} |
139 |
}); |
140 |
updateProfiles(); |
141 |
checkOkOption(); |
142 |
} |
143 |
|
144 |
boolean shouldUpdateProfile() { |
145 |
return changeProfile.isSelected(); |
146 |
} |
147 |
|
148 |
@CheckForNull |
149 |
String getProfile() { |
150 |
final Object selObj = profiles.getSelectedItem(); |
151 |
if (selObj instanceof Integer) { |
152 |
return getProfileName((Integer)selObj); |
153 |
} else { |
154 |
return null; |
155 |
} |
156 |
} |
157 |
|
158 |
@NonNull |
159 |
Collection<? extends URI> getRootsToRemove() { |
160 |
return libsModel.getRemovedRooots(); |
161 |
} |
162 |
|
163 |
@CheckForNull |
164 |
static String normalize(@NullAllowed String profile) { |
165 |
return profile != null && PROFILE_PATTERN.matcher(profile).matches() ? |
166 |
profile : |
167 |
null; |
168 |
} |
169 |
|
170 |
@CheckForNull |
171 |
static String requiredProfile(@NonNull final Map<String,Map<URI,String>> state) { |
172 |
String current = null; |
173 |
for (Map.Entry<String,Map<URI,String>> cpe : state.entrySet()) { |
174 |
current = requiredProfile(cpe.getValue().entrySet(), current); |
175 |
} |
176 |
return current; |
177 |
} |
178 |
|
179 |
@CheckForNull |
180 |
private static String requiredProfile( |
181 |
@NonNull final Collection<? extends Map.Entry<URI,String>> state, |
182 |
@NullAllowed String current) { |
183 |
for (Map.Entry<URI,String> re : state) { |
184 |
current = max(current, re.getValue()); |
185 |
} |
186 |
return current; |
187 |
} |
188 |
|
189 |
@CheckForNull |
190 |
private static String max( |
191 |
@NullAllowed String profileA, |
192 |
@NullAllowed String profileB) { |
193 |
profileA = normalize(profileA); |
194 |
profileB = normalize(profileB); |
195 |
if (profileA == null) { |
196 |
return profileB; |
197 |
} |
198 |
if (profileB == null) { |
199 |
return profileA; |
200 |
} |
201 |
return profileA.compareTo(profileB) < 0 ? |
202 |
profileB : |
203 |
profileA; |
204 |
} |
205 |
|
206 |
private static int getProfileIndex(@NullAllowed final String profileName) { |
207 |
if (profileName != null) { |
208 |
final Matcher m = PROFILE_PATTERN.matcher(profileName); |
209 |
if (m.matches()) { |
210 |
return Integer.parseInt(m.group(1)); |
211 |
} |
212 |
} |
213 |
return FULL_JRE; |
214 |
} |
215 |
|
216 |
@CheckForNull |
217 |
private static String getProfileName(final int index) { |
218 |
if (index <= 0 || index > FULL_JRE) { |
219 |
throw new IndexOutOfBoundsException( |
220 |
String.format( |
221 |
"Index: %d", //NOI18N |
222 |
index)); |
223 |
} |
224 |
if (index == FULL_JRE) { |
225 |
return null; |
226 |
} |
227 |
return String.format(PROFILE_FORMAT,index); |
228 |
} |
229 |
|
230 |
private void updateProfiles() { |
231 |
profiles.removeAllItems(); |
232 |
final int required = getProfileIndex(reqProfile); |
233 |
for (int i = required; i<= FULL_JRE; i++) { |
234 |
profiles.addItem(i); |
235 |
} |
236 |
profiles.setSelectedItem(required); |
237 |
} |
238 |
|
239 |
private void checkOkOption() { |
240 |
okOption.setEnabled(libsModel.getSize() == 0); |
241 |
} |
242 |
|
243 |
private static final class ProfilesRenderer extends DefaultListCellRenderer { |
244 |
@Override |
245 |
@NbBundle.Messages({ |
246 |
"NAME_Compact1=Compact 1", |
247 |
"NAME_Compact2=Compact 2", |
248 |
"NAME_Compact3=Compact 3", |
249 |
"NAME_FullJRE=Full JRE" |
250 |
}) |
251 |
public Component getListCellRendererComponent( |
252 |
@NonNull final JList jlist, |
253 |
@NullAllowed Object o, |
254 |
final int i, |
255 |
final boolean bln, |
256 |
final boolean bln1) { |
257 |
if (o instanceof Integer) { |
258 |
switch ((Integer)o) { |
259 |
case 1: |
260 |
o = Bundle.NAME_Compact1(); |
261 |
break; |
262 |
case 2: |
263 |
o = Bundle.NAME_Compact2(); |
264 |
break; |
265 |
case 3: |
266 |
o = Bundle.NAME_Compact3(); |
267 |
break; |
268 |
case FULL_JRE: |
269 |
o = Bundle.NAME_FullJRE(); |
270 |
break; |
271 |
default: |
272 |
throw new IllegalArgumentException(o.toString()); |
273 |
} |
274 |
} |
275 |
return super.getListCellRendererComponent(jlist, o, i, bln, bln1); //To change body of generated methods, choose Tools | Templates. |
276 |
} |
277 |
} |
278 |
|
279 |
@NbBundle.Messages({ |
280 |
"FMT_RootWithProfile={0} ({1})" |
281 |
}) |
282 |
private static final class LibsRenderer extends DefaultListCellRenderer { |
283 |
@Override |
284 |
public Component getListCellRendererComponent( |
285 |
@NonNull final JList jlist, |
286 |
@NullAllowed Object o, |
287 |
final int i, |
288 |
final boolean bln, |
289 |
final boolean bln1) { |
290 |
String toolTip = null; |
291 |
if (o instanceof Map.Entry) { |
292 |
final Map.Entry<URI,String> e = (Map.Entry<URI, String>) o; |
293 |
final String profile = e.getValue(); |
294 |
String simpleName; |
295 |
try { |
296 |
final URL root = e.getKey().toURL(); |
297 |
URL fileURL = FileUtil.getArchiveFile(root); |
298 |
if (fileURL == null) { |
299 |
fileURL = root; |
300 |
} |
301 |
final File f = Utilities.toFile(fileURL.toURI()); |
302 |
simpleName = f.getName(); |
303 |
toolTip = f.getAbsolutePath(); |
304 |
} catch (URISyntaxException ex) { |
305 |
simpleName = e.getKey().toString(); |
306 |
} catch (MalformedURLException ex) { |
307 |
simpleName = e.getKey().toString(); |
308 |
} |
309 |
o = Bundle.FMT_RootWithProfile(simpleName, profile); |
310 |
} |
311 |
final Component res = super.getListCellRendererComponent(jlist, o, i, bln, bln1); //To change body of generated methods, choose Tools | Templates. |
312 |
setToolTipText(toolTip); |
313 |
return res; |
314 |
} |
315 |
} |
316 |
|
317 |
private static final class LibsModel extends AbstractListModel { |
318 |
|
319 |
private final String currentProfile; |
320 |
private final Map<String,Map<URI,String>> state; |
321 |
private final Set<URI> toRemove; |
322 |
private final List<Map.Entry<URI,String>> data; |
323 |
private boolean updated; |
324 |
|
325 |
LibsModel( |
326 |
@NonNull final String currentProfile, |
327 |
@NonNull final Map<String,Map<URI,String>> state) { |
328 |
this.currentProfile = currentProfile; |
329 |
this.state = state; |
330 |
this.toRemove = new HashSet<URI>(); |
331 |
this.data = new ArrayList<Map.Entry<URI, String>>(); |
332 |
refresh(); |
333 |
} |
334 |
|
335 |
@Override |
336 |
public int getSize() { |
337 |
return data.size(); |
338 |
} |
339 |
|
340 |
@Override |
341 |
public Object getElementAt(int i) { |
342 |
if (i<0 || i>=data.size()) { |
343 |
throw new IndexOutOfBoundsException( |
344 |
String.format( |
345 |
"Index: %d, Size: %d", //NOI18N |
346 |
i, |
347 |
data.size())); |
348 |
} |
349 |
return data.get(i); |
350 |
} |
351 |
|
352 |
void removeRoots(@NonNull final Collection<? extends URI> root) { |
353 |
final int oldSize = getSize(); |
354 |
toRemove.addAll(root); |
355 |
refresh(); |
356 |
final int newSize = getSize(); |
357 |
fireContentsChanged(this, 0, Math.max(oldSize, newSize)); |
358 |
}; |
359 |
|
360 |
@CheckForNull |
361 |
String requiredProfile() { |
362 |
return FixProfile.requiredProfile(data, currentProfile); |
363 |
} |
364 |
|
365 |
void updateProfile(final boolean update) { |
366 |
final int oldSize = getSize(); |
367 |
updated = update; |
368 |
refresh(); |
369 |
final int newSize = getSize(); |
370 |
fireContentsChanged(this, 0, Math.max(oldSize, newSize)); |
371 |
} |
372 |
|
373 |
@NonNull |
374 |
Collection<? extends URI> getRemovedRooots() { |
375 |
return Collections.unmodifiableCollection(toRemove); |
376 |
} |
377 |
|
378 |
private void refresh() { |
379 |
final Set<Map.Entry<URI,String>> newData = new HashSet<Map.Entry<URI,String>>(); |
380 |
for (Map.Entry<String,Map<URI,String>> cpe : state.entrySet()) { |
381 |
for (Map.Entry<URI,String> re : cpe.getValue().entrySet()) { |
382 |
if (!toRemove.contains(re.getKey()) && |
383 |
!(updated && PROFILE_PATTERN.matcher(re.getValue()).matches())) { |
384 |
newData.add(re); |
385 |
} |
386 |
} |
387 |
} |
388 |
data.clear(); |
389 |
data.addAll(newData); |
390 |
} |
391 |
} |
392 |
|
393 |
/** |
394 |
* This method is called from within the constructor to initialize the form. |
395 |
* WARNING: Do NOT modify this code. The content of this method is always |
396 |
* regenerated by the Form Editor. |
397 |
*/ |
398 |
@SuppressWarnings("unchecked") |
399 |
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents |
400 |
private void initComponents() { |
401 |
|
402 |
jLabel1 = new javax.swing.JLabel(); |
403 |
remove = new javax.swing.JButton(); |
404 |
changeProfile = new javax.swing.JCheckBox(); |
405 |
profiles = new javax.swing.JComboBox(); |
406 |
jScrollPane1 = new javax.swing.JScrollPane(); |
407 |
brokenLibs = new javax.swing.JList(); |
408 |
|
409 |
jLabel1.setLabelFor(brokenLibs); |
410 |
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(FixProfile.class, "LBL_FixProfile_BrokenLibs")); // NOI18N |
411 |
|
412 |
org.openide.awt.Mnemonics.setLocalizedText(remove, org.openide.util.NbBundle.getMessage(FixProfile.class, "LBL_FixProfile_remove")); // NOI18N |
413 |
remove.setToolTipText(org.openide.util.NbBundle.getMessage(FixProfile.class, "TIP_FixProfile_Remove")); // NOI18N |
414 |
remove.addActionListener(new java.awt.event.ActionListener() { |
415 |
public void actionPerformed(java.awt.event.ActionEvent evt) { |
416 |
removeLibrary(evt); |
417 |
} |
418 |
}); |
419 |
|
420 |
org.openide.awt.Mnemonics.setLocalizedText(changeProfile, org.openide.util.NbBundle.getMessage(FixProfile.class, "LBL_FixProfile_changeProfile")); // NOI18N |
421 |
|
422 |
jScrollPane1.setViewportView(brokenLibs); |
423 |
brokenLibs.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(FixProfile.class, "AD_FixProfile_BrokenLibs")); // NOI18N |
424 |
|
425 |
org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this); |
426 |
this.setLayout(layout); |
427 |
layout.setHorizontalGroup( |
428 |
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) |
429 |
.add(layout.createSequentialGroup() |
430 |
.addContainerGap() |
431 |
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) |
432 |
.add(layout.createSequentialGroup() |
433 |
.add(jLabel1) |
434 |
.addContainerGap(154, Short.MAX_VALUE)) |
435 |
.add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() |
436 |
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) |
437 |
.add(org.jdesktop.layout.GroupLayout.LEADING, layout.createSequentialGroup() |
438 |
.add(changeProfile) |
439 |
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) |
440 |
.add(profiles, 0, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) |
441 |
.add(jScrollPane1)) |
442 |
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) |
443 |
.add(remove) |
444 |
.addContainerGap()))) |
445 |
); |
446 |
layout.setVerticalGroup( |
447 |
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) |
448 |
.add(layout.createSequentialGroup() |
449 |
.addContainerGap() |
450 |
.add(jLabel1) |
451 |
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) |
452 |
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) |
453 |
.add(layout.createSequentialGroup() |
454 |
.add(remove) |
455 |
.add(0, 0, Short.MAX_VALUE)) |
456 |
.add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 212, Short.MAX_VALUE)) |
457 |
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) |
458 |
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) |
459 |
.add(changeProfile) |
460 |
.add(profiles, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) |
461 |
.addContainerGap()) |
462 |
); |
463 |
|
464 |
jLabel1.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(FixProfile.class, "FixProfile.jLabel1.AccessibleContext.accessibleName")); // NOI18N |
465 |
changeProfile.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(FixProfile.class, "AD_FixProfile_changeProfile")); // NOI18N |
466 |
profiles.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(FixProfile.class, "AN_FixProfile_Profiles")); // NOI18N |
467 |
profiles.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(FixProfile.class, "AD_FixProfile_Profiles")); // NOI18N |
468 |
}// </editor-fold>//GEN-END:initComponents |
469 |
|
470 |
private void removeLibrary(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeLibrary |
471 |
final Object[] selection = brokenLibs.getSelectedValues(); |
472 |
final Set<URI> rootsToRemove = new HashSet<URI>(); |
473 |
for (Object e : selection) { |
474 |
rootsToRemove.add(((Map.Entry<URI,String>)e).getKey()); |
475 |
} |
476 |
libsModel.removeRoots(rootsToRemove); |
477 |
if (libsModel.getSize() > 0) { |
478 |
brokenLibs.setSelectedIndex(0); |
479 |
} |
480 |
reqProfile = libsModel.requiredProfile(); |
481 |
updateProfiles(); |
482 |
}//GEN-LAST:event_removeLibrary |
483 |
|
484 |
// Variables declaration - do not modify//GEN-BEGIN:variables |
485 |
private javax.swing.JList brokenLibs; |
486 |
private javax.swing.JCheckBox changeProfile; |
487 |
private javax.swing.JLabel jLabel1; |
488 |
private javax.swing.JScrollPane jScrollPane1; |
489 |
private javax.swing.JComboBox profiles; |
490 |
private javax.swing.JButton remove; |
491 |
// End of variables declaration//GEN-END:variables |
492 |
} |