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.autoupdate.ui; |
43 |
|
44 |
import java.awt.Dialog; |
45 |
import java.awt.event.ActionEvent; |
46 |
import java.awt.event.ActionListener; |
47 |
import java.io.IOException; |
48 |
import java.util.ArrayList; |
49 |
import java.util.Arrays; |
50 |
import java.util.Collection; |
51 |
import java.util.Iterator; |
52 |
import java.util.List; |
53 |
import java.util.Set; |
54 |
import java.util.logging.Level; |
55 |
import java.util.logging.Logger; |
56 |
import javax.swing.JButton; |
57 |
import javax.swing.JComponent; |
58 |
import javax.swing.JLabel; |
59 |
import javax.swing.JPanel; |
60 |
import javax.swing.JScrollPane; |
61 |
import javax.swing.JTextArea; |
62 |
import org.netbeans.api.autoupdate.InstallSupport; |
63 |
import org.netbeans.api.autoupdate.OperationContainer; |
64 |
import org.netbeans.api.autoupdate.OperationException; |
65 |
import org.netbeans.api.autoupdate.OperationSupport; |
66 |
import org.netbeans.api.autoupdate.OperationSupport.Restarter; |
67 |
import org.netbeans.api.autoupdate.UpdateElement; |
68 |
import org.netbeans.api.autoupdate.UpdateManager; |
69 |
import org.netbeans.api.autoupdate.UpdateUnit; |
70 |
import org.netbeans.api.autoupdate.UpdateUnitProvider; |
71 |
import org.netbeans.api.autoupdate.UpdateUnitProviderFactory; |
72 |
import org.netbeans.api.options.OptionsDisplayer; |
73 |
import org.netbeans.api.progress.ProgressHandle; |
74 |
import org.netbeans.api.progress.ProgressHandleFactory; |
75 |
import org.netbeans.modules.autoupdate.ui.api.PluginManager; |
76 |
import org.openide.DialogDescriptor; |
77 |
import org.openide.DialogDisplayer; |
78 |
import org.openide.NotifyDescriptor; |
79 |
import org.openide.awt.Mnemonics; |
80 |
import org.openide.util.NbBundle.Messages; |
81 |
import org.openide.util.RequestProcessor; |
82 |
import static org.netbeans.modules.autoupdate.ui.Bundle.*; |
83 |
|
84 |
/** |
85 |
* |
86 |
* @author Jesse Glick |
87 |
* @author Jan Lahoda |
88 |
* @author Petr Hejl |
89 |
*/ |
90 |
public class ModuleInstallerSupport { |
91 |
private static RequestProcessor RP = new RequestProcessor(ModuleInstallerSupport.class.getName(), 1); |
92 |
private static final Logger LOG = Logger.getLogger(ModuleInstallerSupport.class.getName()); |
93 |
|
94 |
@Messages({ |
95 |
"searching_handle_single=Searching for \"{0}\" module on NetBeans plugin portal...", |
96 |
"resolve_title_single=Resolve \"{0}\" Reference Problem", |
97 |
"nodownload_header_single=\"{0}\" module has not been downloaded", |
98 |
"nodownload_message_single=You can try to download \"{0}\" module again", |
99 |
"active_handle_single=Activating {0}", |
100 |
|
101 |
"searching_handle=Searching for modules on NetBeans plugin portal...", |
102 |
"resolve_title=Resolve Reference Problem", |
103 |
"nodownload_header=Modules have not been downloaded", |
104 |
"nodownload_message=You can try to download modules again", |
105 |
"active_handle=Activating modules", |
106 |
|
107 |
"networkproblem_header=Unable to connect to the NetBeans plugin portal", |
108 |
"networkproblem_message=Check your proxy settings or try again later. " |
109 |
+ "The server may be unavailable at the moment. " |
110 |
+ "You may also want to make sure that your firewall is not blocking network traffic.", |
111 |
"proxy_button=&Proxy Settings...", |
112 |
"tryagain_button=Try &Again" |
113 |
}) |
114 |
|
115 |
private final Object[] closingOptions; |
116 |
|
117 |
private Object[] fullClosingOptions; |
118 |
private JButton tryAgain; |
119 |
private JButton proxySettings; |
120 |
|
121 |
public ModuleInstallerSupport(Object... alternativeOptions) { |
122 |
this.closingOptions = alternativeOptions.clone(); |
123 |
} |
124 |
|
125 |
public Object installPlugins(final String displayName, Set<String> cnbs) throws OperationException { |
126 |
Collection<UpdateUnit> units = findModules(cnbs); |
127 |
if (units == null) { |
128 |
final String searchMessage = displayName != null |
129 |
? searching_handle_single(displayName) : searching_handle(); |
130 |
final String resolveTitle = displayName != null |
131 |
? resolve_title_single(displayName) : resolve_title(); |
132 |
|
133 |
final ProgressHandle handle = ProgressHandleFactory.createHandle(searchMessage); |
134 |
initButtons(); |
135 |
final DialogDescriptor searching = new DialogDescriptor(searchingPanel(new JLabel(searchMessage), |
136 |
ProgressHandleFactory.createProgressComponent(handle)), resolveTitle, true, null); |
137 |
handle.setInitialDelay(0); |
138 |
handle.start(); |
139 |
searching.setOptions(new Object[] {NotifyDescriptor.CANCEL_OPTION}); |
140 |
searching.setMessageType(NotifyDescriptor.PLAIN_MESSAGE); |
141 |
final Dialog dlg = DialogDisplayer.getDefault().createDialog(searching); |
142 |
RP.post(new Runnable() { |
143 |
|
144 |
@Override |
145 |
public void run() { |
146 |
// May be first start, when no update lists have yet been downloaded. |
147 |
try { |
148 |
for (UpdateUnitProvider p : UpdateUnitProviderFactory.getDefault().getUpdateUnitProviders(true)) { |
149 |
p.refresh(handle, true); |
150 |
} |
151 |
// close searching |
152 |
dlg.dispose(); |
153 |
} catch (IOException ex) { |
154 |
LOG.log(Level.FINE, ex.getMessage(), ex); |
155 |
if (!dlg.isVisible()) { |
156 |
LOG.fine("dialog not visible => do nothing"); |
157 |
return; |
158 |
} |
159 |
DialogDescriptor networkProblem = new DialogDescriptor( |
160 |
problemPanel(resolveTitle, networkproblem_message()), // message |
161 |
networkproblem_header(), // title |
162 |
true, // modal |
163 |
null); |
164 |
networkProblem.setOptions(new Object[] {tryAgain, proxySettings, NotifyDescriptor.CANCEL_OPTION}); |
165 |
networkProblem.setAdditionalOptions(closingOptions); |
166 |
networkProblem.setClosingOptions(fullClosingOptions); |
167 |
networkProblem.setMessageType(NotifyDescriptor.WARNING_MESSAGE); |
168 |
Dialog networkProblemDialog = DialogDisplayer.getDefault().createDialog(networkProblem); |
169 |
networkProblemDialog.setVisible(true); |
170 |
Object answer = networkProblem.getValue(); |
171 |
if (NotifyDescriptor.CANCEL_OPTION.equals(answer) |
172 |
|| Arrays.asList(closingOptions).contains(answer) |
173 |
|| answer.equals(NotifyDescriptor.DEFAULT_OPTION) /* escape */ ) { |
174 |
LOG.fine("cancel network problem dialog"); |
175 |
searching.setValue(answer); |
176 |
dlg.dispose(); |
177 |
} else if (tryAgain.equals(answer)) { |
178 |
LOG.fine("try again searching"); |
179 |
RP.post(this); |
180 |
} else { |
181 |
assert false : "Unknown " + answer; |
182 |
} |
183 |
} |
184 |
} |
185 |
}); |
186 |
dlg.setVisible(true); |
187 |
handle.finish(); |
188 |
if (NotifyDescriptor.CANCEL_OPTION.equals(searching.getValue()) |
189 |
|| searching.getValue().equals(NotifyDescriptor.DEFAULT_OPTION) /* escape */) { |
190 |
LOG.log(Level.FINE, "user canceled searching for {0}", cnbs); |
191 |
return showNoDownloadDialog(displayName, cnbs); |
192 |
} else if (Arrays.asList(closingOptions).contains(searching.getValue())){ |
193 |
return searching.getValue(); |
194 |
} |
195 |
units = findModules(cnbs); |
196 |
if (units == null) { |
197 |
LOG.log(Level.FINE, "could not find {0} on any update site", cnbs); |
198 |
return showNoDownloadDialog(displayName, cnbs); |
199 |
} |
200 |
} |
201 |
|
202 |
List<UpdateUnit> toHandle = new ArrayList<UpdateUnit>(units); |
203 |
OperationContainer<OperationSupport> oc = null; |
204 |
|
205 |
for (Iterator<UpdateUnit> it = toHandle.iterator(); it.hasNext(); ) { |
206 |
UpdateUnit unit = it.next(); |
207 |
|
208 |
// check if module installed |
209 |
if (unit.getInstalled() != null) { |
210 |
if (LOG.isLoggable(Level.FINE)) { |
211 |
LOG.fine(unit.getInstalled() + " already installed. Is active? " + unit.getInstalled().isEnabled()); |
212 |
} |
213 |
if (unit.getInstalled().isEnabled()) { |
214 |
it.remove(); |
215 |
continue; |
216 |
} else { |
217 |
if (oc == null) { |
218 |
oc = OperationContainer.createForEnable(); |
219 |
} |
220 |
if (!oc.canBeAdded(unit, unit.getInstalled())) { |
221 |
throw new OperationException(OperationException.ERROR_TYPE.ENABLE, |
222 |
"could not add " + unit.getInstalled() + " for activation"); |
223 |
} |
224 |
for (UpdateElement req : oc.add(unit.getInstalled()).getRequiredElements()) { |
225 |
oc.add(req); |
226 |
} |
227 |
it.remove(); |
228 |
continue; |
229 |
} |
230 |
} |
231 |
} |
232 |
|
233 |
if (oc != null) { |
234 |
ProgressHandle activeHandle = ProgressHandleFactory.createHandle( |
235 |
displayName != null ? active_handle_single(displayName) : active_handle()); |
236 |
Restarter restarter = oc.getSupport().doOperation(activeHandle); |
237 |
assert restarter == null : "No Restater need to make units active"; |
238 |
} |
239 |
|
240 |
if (toHandle.isEmpty()) { |
241 |
return null; |
242 |
} |
243 |
|
244 |
OperationContainer<InstallSupport> ocInstall = OperationContainer.createForInstall(); |
245 |
for (Iterator<UpdateUnit> it = toHandle.iterator(); it.hasNext(); ) { |
246 |
UpdateUnit unit = it.next(); |
247 |
|
248 |
List<UpdateElement> updates = unit.getAvailableUpdates(); |
249 |
if (updates.isEmpty()) { |
250 |
throw new OperationException(OperationException.ERROR_TYPE.INSTALL, "no updates for " + unit); |
251 |
} |
252 |
|
253 |
UpdateElement element = updates.get(0); |
254 |
if (!ocInstall.canBeAdded(unit, element)) { |
255 |
throw new OperationException(OperationException.ERROR_TYPE.INSTALL, "could not add " + element + " to updates"); |
256 |
} |
257 |
for (UpdateElement req : ocInstall.add(element).getRequiredElements()) { |
258 |
ocInstall.add(req); |
259 |
} |
260 |
it.remove(); |
261 |
} |
262 |
assert toHandle.isEmpty() : "These unit were not handled " + toHandle; |
263 |
|
264 |
if (!PluginManager.openInstallWizard(ocInstall)) { |
265 |
LOG.fine("user canceled PM"); |
266 |
return showNoDownloadDialog(displayName, cnbs); |
267 |
} |
268 |
return null; |
269 |
} |
270 |
|
271 |
private Collection<UpdateUnit> findModules(Set<String> cnbs) { |
272 |
List<UpdateUnit> ret = new ArrayList<UpdateUnit>(cnbs.size()); |
273 |
for (UpdateUnit unit : UpdateManager.getDefault().getUpdateUnits(UpdateManager.TYPE.MODULE)) { |
274 |
if (cnbs.contains(unit.getCodeName())) { |
275 |
ret.add(unit); |
276 |
if (ret.size() == cnbs.size()) { |
277 |
break; |
278 |
} |
279 |
} |
280 |
} |
281 |
if (ret.size() == cnbs.size()) { |
282 |
return ret; |
283 |
} |
284 |
return null; |
285 |
} |
286 |
|
287 |
private void initButtons() { |
288 |
if (tryAgain != null) { |
289 |
return ; |
290 |
} |
291 |
tryAgain = new JButton(); |
292 |
proxySettings = new JButton(); |
293 |
Mnemonics.setLocalizedText(tryAgain, tryagain_button()); |
294 |
Mnemonics.setLocalizedText(proxySettings, proxy_button()); |
295 |
proxySettings.addActionListener(new ActionListener() { |
296 |
@Override |
297 |
public void actionPerformed(ActionEvent e) { |
298 |
LOG.fine("show proxy options"); |
299 |
OptionsDisplayer.getDefault().open("General"); // NOI18N |
300 |
} |
301 |
}); |
302 |
fullClosingOptions = new Object[closingOptions.length + 2]; |
303 |
System.arraycopy(closingOptions, 0, fullClosingOptions, 0, closingOptions.length); |
304 |
fullClosingOptions[fullClosingOptions.length - 2] = tryAgain; |
305 |
fullClosingOptions[fullClosingOptions.length - 1] = NotifyDescriptor.CANCEL_OPTION; |
306 |
} |
307 |
|
308 |
private Object showNoDownloadDialog(String displayName, Set<String> cnbs) throws OperationException { |
309 |
DialogDescriptor networkProblem; |
310 |
if (displayName != null) { |
311 |
networkProblem = new DialogDescriptor( |
312 |
problemPanel(nodownload_header_single(displayName), nodownload_message_single(displayName)), // message |
313 |
resolve_title_single(displayName), // title |
314 |
true, // modal |
315 |
null); |
316 |
} else { |
317 |
networkProblem = new DialogDescriptor( |
318 |
problemPanel(nodownload_header(), nodownload_message()), // message |
319 |
resolve_title(), // title |
320 |
true, // modal |
321 |
null); |
322 |
} |
323 |
initButtons(); |
324 |
networkProblem.setOptions(new Object[] {tryAgain, NotifyDescriptor.CANCEL_OPTION}); |
325 |
networkProblem.setAdditionalOptions(closingOptions); |
326 |
networkProblem.setClosingOptions(fullClosingOptions); |
327 |
networkProblem.setMessageType(NotifyDescriptor.WARNING_MESSAGE); |
328 |
Dialog networkProblemDialog = DialogDisplayer.getDefault().createDialog(networkProblem); |
329 |
networkProblemDialog.setVisible(true); |
330 |
Object answer = networkProblem.getValue(); |
331 |
if (NotifyDescriptor.CANCEL_OPTION.equals(answer) |
332 |
|| Arrays.asList(closingOptions).contains(answer) |
333 |
|| answer.equals(NotifyDescriptor.DEFAULT_OPTION) /* escape */ ) { |
334 |
LOG.fine("cancel no download dialog"); |
335 |
//throw new InterruptedException("user canceled download & install JUnit"); |
336 |
return answer; |
337 |
} else if (tryAgain.equals(answer)) { |
338 |
LOG.fine("try again download()"); |
339 |
return installPlugins(displayName, cnbs); |
340 |
} else { |
341 |
assert false : "Unknown " + answer; |
342 |
} |
343 |
assert false : "Unknown " + answer; |
344 |
return NotifyDescriptor.DEFAULT_OPTION; |
345 |
} |
346 |
|
347 |
private static JPanel searchingPanel(JLabel progressLabel, JComponent progressComponent) { |
348 |
JPanel panel = new JPanel(); |
349 |
progressLabel.setLabelFor(progressComponent); |
350 |
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(panel); |
351 |
panel.setLayout(layout); |
352 |
layout.setHorizontalGroup( |
353 |
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
354 |
.addGroup(layout.createSequentialGroup() |
355 |
.addContainerGap() |
356 |
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) |
357 |
.addComponent(progressLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) |
358 |
.addComponent(progressComponent, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 399, Short.MAX_VALUE)) |
359 |
.addContainerGap()) |
360 |
); |
361 |
layout.setVerticalGroup( |
362 |
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
363 |
.addGroup(layout.createSequentialGroup() |
364 |
.addGap(96, 96, 96) |
365 |
.addComponent(progressLabel) |
366 |
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) |
367 |
.addComponent(progressComponent, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) |
368 |
.addContainerGap(109, Short.MAX_VALUE)) |
369 |
); |
370 |
return panel; |
371 |
} |
372 |
|
373 |
private static JPanel problemPanel(String header, String message) { |
374 |
JPanel panel = new JPanel(); |
375 |
JLabel jLabel1 = new javax.swing.JLabel(); |
376 |
JScrollPane jScrollPane1 = new javax.swing.JScrollPane(); |
377 |
JTextArea jTextArea1 = new javax.swing.JTextArea(); |
378 |
|
379 |
jLabel1.setFont(jLabel1.getFont().deriveFont(jLabel1.getFont().getStyle() | java.awt.Font.BOLD)); |
380 |
jLabel1.setText(header); |
381 |
|
382 |
jTextArea1.setColumns(20); |
383 |
jTextArea1.setEditable(false); |
384 |
jTextArea1.setLineWrap(true); |
385 |
jTextArea1.setWrapStyleWord(true); |
386 |
jTextArea1.setRows(5); |
387 |
jTextArea1.setText(message); |
388 |
jTextArea1.setOpaque(false); |
389 |
jScrollPane1.setViewportView(jTextArea1); |
390 |
|
391 |
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(panel); |
392 |
panel.setLayout(layout); |
393 |
layout.setHorizontalGroup( |
394 |
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
395 |
.addGroup(layout.createSequentialGroup() |
396 |
.addContainerGap() |
397 |
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
398 |
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 478, Short.MAX_VALUE) |
399 |
.addGroup(layout.createSequentialGroup() |
400 |
.addComponent(jLabel1) |
401 |
.addGap(107, 107, 107))) |
402 |
.addContainerGap()) |
403 |
); |
404 |
layout.setVerticalGroup( |
405 |
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) |
406 |
.addGroup(layout.createSequentialGroup() |
407 |
.addContainerGap() |
408 |
.addComponent(jLabel1) |
409 |
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) |
410 |
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 133, Short.MAX_VALUE) |
411 |
.addGap(82, 82, 82)) |
412 |
); |
413 |
return panel; |
414 |
} |
415 |
|
416 |
} |
417 |
|