blob: 08b38993a8897e52e17625298f25858f5cbfc995 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.nbform;
import java.awt.event.ActionEvent;
import org.netbeans.api.autoupdate.OperationSupport;
import org.netbeans.api.autoupdate.OperationSupport.Restarter;
import org.netbeans.api.options.OptionsDisplayer;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JPanel;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.awt.Dialog;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JLabel;
import org.openide.DialogDisplayer;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Callable;
import javax.swing.GroupLayout;
import javax.swing.JScrollPane;
import javax.swing.LayoutStyle;
import org.netbeans.api.autoupdate.InstallSupport;
import org.netbeans.api.autoupdate.OperationContainer;
import org.netbeans.api.autoupdate.UpdateElement;
import org.netbeans.api.autoupdate.UpdateManager;
import org.netbeans.api.autoupdate.UpdateUnit;
import org.netbeans.api.autoupdate.UpdateUnitProvider;
import org.netbeans.api.autoupdate.UpdateUnitProviderFactory;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.api.project.libraries.Library;
import org.netbeans.api.project.libraries.LibraryManager;
import org.netbeans.modules.autoupdate.ui.api.PluginManager;
import org.netbeans.modules.form.FormUtils;
import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport.LibraryDefiner;
import org.openide.DialogDescriptor;
import org.openide.NotifyDescriptor;
import org.openide.awt.Mnemonics;
import org.openide.util.RequestProcessor;
import org.openide.util.lookup.ServiceProvider;
/**
* Defines Swing Application Framework Library by downloading swingapplib module.
* The code is based on {@code JUnitLibraryDownloader} almost literally.
*
* @author Jan Stola
*/
@ServiceProvider(service=LibraryDefiner.class)
public class SwingAppLibDownloader implements LibraryDefiner {
private static RequestProcessor RP = new RequestProcessor(SwingAppLibDownloader.class.getName(), 1);
private static final Logger LOG = Logger.getLogger(SwingAppLibDownloader.class.getName());
@Override
public Callable<Library> missingLibrary(final String name) {
if (!name.matches("swing-app-framework")) { // NOI18N
return null;
}
return new Callable<Library>() {
@Override
public Library call() throws Exception {
return download(name);
}
};
}
private JButton libraryManager;
private JButton tryAgain;
private JButton proxySettings;
@SuppressWarnings("SleepWhileInLoop") // NOI18N
private Library download(String name) throws Exception {
UpdateUnit unit = findSwingAppLibModule();
if (unit == null) {
String searchingHandleTxt = FormUtils.getBundleString("swingapp.searching_handle"); // NOI18N
final ProgressHandle handle = ProgressHandleFactory.createHandle(searchingHandleTxt);
initButtons();
final DialogDescriptor searching = new DialogDescriptor(
searchingPanel(new JLabel(searchingHandleTxt), ProgressHandleFactory.createProgressComponent(handle)),
FormUtils.getBundleString("swingapp.resolve_title"), true, null); // NOI18N
handle.setInitialDelay(0);
handle.start();
searching.setOptions(new Object[] {NotifyDescriptor.CANCEL_OPTION});
searching.setMessageType(NotifyDescriptor.PLAIN_MESSAGE);
final Dialog dlg = DialogDisplayer.getDefault().createDialog(searching);
RP.post(new Runnable() {
@Override
public void run() {
// May be first start, when no update lists have yet been downloaded.
try {
for (UpdateUnitProvider p : UpdateUnitProviderFactory.getDefault().getUpdateUnitProviders(true)) {
p.refresh(handle, true);
}
// close searching
dlg.dispose();
} catch (IOException ex) {
Logger.getLogger(SwingAppLibDownloader.class.getName()).log(Level.FINE, ex.getMessage(), ex);
if (!dlg.isVisible()) {
LOG.fine("dialog not visible => do nothing"); // NOI18N
return ;
}
DialogDescriptor networkProblem = new DialogDescriptor(
problemPanel(FormUtils.getBundleString("swingapp.resolve_title"), FormUtils.getBundleString("swingapp.networkproblem_message")), // NOI18N
FormUtils.getBundleString("swingapp.networkproblem_header"), // NOI18N
true, // modal
null);
networkProblem.setOptions(new Object[] {tryAgain, proxySettings, NotifyDescriptor.CANCEL_OPTION});
networkProblem.setAdditionalOptions(new Object[] {libraryManager});
networkProblem.setClosingOptions(new Object[] {libraryManager, tryAgain, NotifyDescriptor.CANCEL_OPTION});
networkProblem.setMessageType(NotifyDescriptor.WARNING_MESSAGE);
Dialog networkProblemDialog = DialogDisplayer.getDefault().createDialog(networkProblem);
networkProblemDialog.setVisible(true);
Object answer = networkProblem.getValue();
if (NotifyDescriptor.CANCEL_OPTION.equals(answer) || answer.equals(-1) /* escape */ ) {
LOG.fine("cancel network problem dialog"); // NOI18N
searching.setValue(answer);
dlg.dispose();
} else if (tryAgain.equals(answer)) {
LOG.fine("try again searching"); // NOI18N
RP.post(this);
} else if (libraryManager.equals(answer)) {
LOG.fine("open library manager"); // NOI18N
searching.setValue(answer);
dlg.dispose();
} else {
assert false : "Unknown " + answer; // NOI18N
}
}
}
});
dlg.setVisible(true);
handle.finish();
if (NotifyDescriptor.CANCEL_OPTION.equals(searching.getValue()) || searching.getValue().equals(-1) /* escape */) {
LOG.fine("user canceled searching swingapplib"); // NOI18N
return showNoDownloadDialog(name);
} else if (libraryManager.equals(searching.getValue())) {
throw new Exception("user canceled searching"); // NOI18N
}
unit = findSwingAppLibModule();
if (unit == null) {
LOG.fine("could not find swingapplib on any update site"); // NOI18N
return showNoDownloadDialog(name);
}
}
// check if swingapplib is installed
if (unit.getInstalled() != null) {
LOG.log(Level.FINE, "{0} already installed. Is active? {1}", new Object[]{unit.getInstalled(), unit.getInstalled().isEnabled()}); //NOI18N
if (unit.getInstalled().isEnabled()) {
throw new Exception(unit.getInstalled() + " already installed and active"); // NOI18N
} else {
// activate it
OperationContainer<OperationSupport> oc = OperationContainer.createForEnable();
if (!oc.canBeAdded(unit, unit.getInstalled())) {
throw new Exception("could not add " + unit.getInstalled() + " for activation"); // NOI18N
}
for (UpdateElement req : oc.add(unit.getInstalled()).getRequiredElements()) {
oc.add(req);
}
ProgressHandle activeHandle = ProgressHandleFactory.createHandle (FormUtils.getBundleString("swingapp.active_handle")); // NOI18N
Restarter restarter = oc.getSupport().doOperation(activeHandle);
assert restarter == null : "No Restater need to make " + unit.getInstalled() + " active"; // NOI18N
// XXX new library & build.properties apparently do not show up immediately... how to listen properly?
for (int i = 0; i < 10; i++) {
Library lib = LibraryManager.getDefault().getLibrary(name);
if (lib != null) {
return lib;
}
Thread.sleep(1000);
}
LOG.info("swingapplib failed to make active properly"); // NOI18N
return showNoDownloadDialog(name);
}
}
List<UpdateElement> updates = unit.getAvailableUpdates();
if (updates.isEmpty()) {
throw new Exception("no updates for " + unit); // NOI18N
}
OperationContainer<InstallSupport> oc = OperationContainer.createForInstall();
UpdateElement element = updates.get(0);
if (!oc.canBeAdded(unit, element)) {
throw new Exception("could not add " + element + " to updates"); // NOI18N
}
for (UpdateElement req : oc.add(element).getRequiredElements()) {
oc.add(req);
}
if (!PluginManager.openInstallWizard(oc)) {
LOG.fine("user canceled PM"); // NOI18N
return showNoDownloadDialog(name);
}
// XXX new library & build.properties apparently do not show up immediately... how to listen properly?
for (int i = 0; i < 10; i++) {
Library lib = LibraryManager.getDefault().getLibrary(name);
if (lib != null) {
return lib;
}
Thread.sleep(1000);
}
LOG.info("swingapplib failed to install properly"); // NOI18N
return showNoDownloadDialog(name);
}
private UpdateUnit findSwingAppLibModule() throws IOException {
for (UpdateUnit unit : UpdateManager.getDefault().getUpdateUnits(UpdateManager.TYPE.MODULE)) {
if (unit.getCodeName().equals("org.netbeans.modules.swingapplib")) { // NOI18N
return unit;
}
}
return null;
}
private void initButtons() {
if (libraryManager != null) {
return ;
}
libraryManager = new JButton();
tryAgain = new JButton();
proxySettings = new JButton();
Mnemonics.setLocalizedText(tryAgain, FormUtils.getBundleString("swingapp.tryagain_button")); // NOI18N
Mnemonics.setLocalizedText(libraryManager, FormUtils.getBundleString("swingapp.library_button")); // NOI18N
Mnemonics.setLocalizedText(proxySettings, FormUtils.getBundleString("swingapp.proxy_button")); // NOI18N
proxySettings.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
LOG.fine("show proxy options"); // NOI18N
OptionsDisplayer.getDefault().open("General"); // NOI18N
}
});
}
private Library showNoDownloadDialog(String name) throws Exception {
DialogDescriptor networkProblem = new DialogDescriptor(
problemPanel(FormUtils.getBundleString("swingapp.nodownload_header"), FormUtils.getBundleString("swingapp.nodownload_message")), // NOI18N
FormUtils.getBundleString("swingapp.resolve_title"), // NOI18N
true, // modal
null);
initButtons();
networkProblem.setOptions(new Object[] {tryAgain, NotifyDescriptor.CANCEL_OPTION});
networkProblem.setAdditionalOptions(new Object[] {libraryManager});
networkProblem.setClosingOptions(new Object[] {libraryManager, tryAgain, NotifyDescriptor.CANCEL_OPTION});
networkProblem.setMessageType(NotifyDescriptor.WARNING_MESSAGE);
Dialog networkProblemDialog = DialogDisplayer.getDefault().createDialog(networkProblem);
networkProblemDialog.setVisible(true);
Object answer = networkProblem.getValue();
if (NotifyDescriptor.CANCEL_OPTION.equals(answer) || answer.equals(-1) /* escape */ ) {
LOG.fine("cancel no download dialog"); // NOI18N
return null;
} else if (tryAgain.equals(answer)) {
LOG.fine("try again download()"); // NOI18N
return download(name);
} else if (libraryManager.equals(answer)) {
LOG.fine("open library manager");
throw new Exception("swingapplib failed/canceled to install properly, open library manager instaed");
} else {
assert false : "Unknown " + answer; // NOI18N
}
return null;
}
private static JPanel searchingPanel(JLabel progressLabel, JComponent progressComponent) {
JPanel panel = new JPanel();
progressLabel.setLabelFor(progressComponent);
javax.swing.GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
.addComponent(progressLabel, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(progressComponent, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 399, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(96, 96, 96)
.addComponent(progressLabel)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(progressComponent, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addContainerGap(109, Short.MAX_VALUE))
);
return panel;
}
private static JPanel problemPanel(String header, String message) {
JPanel panel = new JPanel();
JLabel jLabel1 = new javax.swing.JLabel();
JScrollPane jScrollPane1 = new javax.swing.JScrollPane();
JTextArea jTextArea1 = new javax.swing.JTextArea();
jLabel1.setFont(jLabel1.getFont().deriveFont(jLabel1.getFont().getStyle() | java.awt.Font.BOLD));
jLabel1.setText(header);
jTextArea1.setColumns(20);
jTextArea1.setEditable(false);
jTextArea1.setLineWrap(true);
jTextArea1.setWrapStyleWord(true);
jTextArea1.setRows(5);
jTextArea1.setText(message);
jTextArea1.setOpaque(false);
jScrollPane1.setViewportView(jTextArea1);
javax.swing.GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, GroupLayout.DEFAULT_SIZE, 478, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(jLabel1)
.addGap(107, 107, 107)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, GroupLayout.DEFAULT_SIZE, 133, Short.MAX_VALUE)
.addGap(82, 82, 82))
);
return panel;
}
}