| /* |
| * 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.ide.ergonomics.fod; |
| |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.LinkedHashSet; |
| import java.util.Set; |
| import java.util.function.Function; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import javax.swing.JButton; |
| import javax.swing.JComponent; |
| import javax.swing.JTextArea; |
| import javax.swing.SwingUtilities; |
| import org.netbeans.api.autoupdate.InstallSupport; |
| import org.netbeans.api.autoupdate.OperationContainer; |
| import org.netbeans.api.autoupdate.OperationException; |
| import org.netbeans.api.autoupdate.UpdateElement; |
| import org.netbeans.api.progress.ProgressHandle; |
| import org.netbeans.modules.autoupdate.ui.api.PluginManager; |
| import org.openide.DialogDisplayer; |
| import org.openide.NotifyDescriptor; |
| import org.openide.awt.Mnemonics; |
| import org.openide.util.Exceptions; |
| import org.openide.util.NbBundle; |
| import org.openide.util.RequestProcessor; |
| |
| /** |
| * |
| * @author Jirka Rechtacek |
| */ |
| public class ModulesInstaller { |
| |
| private Collection<UpdateElement> modules4install; |
| private RequestProcessor.Task installTask = null; |
| private OperationContainer<InstallSupport> installContainer; |
| private ProgressHandle downloadHandle; |
| private ProgressHandle verifyHandle; |
| private ProgressHandle installHandle; |
| private final FindComponentModules finder; |
| private final ProgressMonitor progressMonitor; |
| |
| public ModulesInstaller (Collection<UpdateElement> modules, FindComponentModules find) { |
| this(modules, find, null); |
| } |
| |
| public ModulesInstaller (Collection<UpdateElement> modules, FindComponentModules find, ProgressMonitor progressMonitor) { |
| if (modules == null || modules.isEmpty ()) { |
| throw new IllegalArgumentException ("Cannot construct InstallerMissingModules with null or empty Collection " + modules); |
| } |
| modules4install = modules; |
| finder = find; |
| if (progressMonitor != null) { |
| this.progressMonitor = progressMonitor; |
| } else { |
| this.progressMonitor = ProgressMonitor.DEV_NULL_PROGRESS_MONITOR; |
| } |
| } |
| |
| static boolean activateModules( |
| boolean askForInstall, ProgressMonitor monitor, FeatureInfo info, |
| Collection<UpdateElement> alreadyOffered, Set<FeatureInfo.ExtraModuleInfo> filter |
| ) { |
| assert ! SwingUtilities.isEventDispatchThread () : "Cannot run in EQ!"; |
| |
| Function<FindComponentModules,Collection<UpdateElement>> toInstall = (state) -> { |
| Collection<UpdateElement> tmp = new LinkedHashSet<>(state.getModulesForInstall()); |
| tmp.removeAll(alreadyOffered); |
| return tmp; |
| }; |
| Function<FindComponentModules,Collection<UpdateElement>> toEnable = (state) -> { |
| return state.getModulesForEnable(); |
| }; |
| |
| FindComponentModules findModules = new FindComponentModules(info, filter); |
| if (askForInstall && !toInstall.apply(findModules).isEmpty()) { |
| OperationContainer<InstallSupport> op = OperationContainer.createForInstall(); |
| op.add(toInstall.apply(findModules)); |
| if (!PluginManager.openInstallWizard(op)) { |
| return false; |
| } |
| findModules = new FindComponentModules(info, filter); |
| if (!toInstall.apply(findModules).isEmpty()) { |
| return false; |
| } |
| } |
| if (!toInstall.apply(findModules).isEmpty()) { |
| ModulesInstaller installer = new ModulesInstaller(toInstall.apply(findModules), findModules, monitor); |
| installer.getInstallTask ().schedule (10); |
| installer.getInstallTask ().waitFinished(); |
| findModules = new FindComponentModules(info, filter); |
| if (!findModules.getModulesForInstall ().isEmpty ()) { |
| return false; |
| } |
| } |
| if (!toEnable.apply(findModules).isEmpty()) { |
| ModulesActivator enabler = new ModulesActivator(toEnable.apply(findModules), findModules, monitor); |
| enabler.getEnableTask ().schedule (100); |
| enabler.getEnableTask ().waitFinished(); |
| } |
| |
| FoDLayersProvider.getInstance().refreshForce(); |
| |
| return true; |
| } |
| |
| public void assignDownloadHandle (ProgressHandle handle) { |
| this.downloadHandle = handle; |
| } |
| |
| public void assignVerifyHandle (ProgressHandle handle) { |
| this.verifyHandle = handle; |
| } |
| |
| public void assignInstallHandle (ProgressHandle handle) { |
| this.installHandle = handle; |
| } |
| |
| public RequestProcessor.Task getInstallTask () { |
| if (installTask == null) { |
| installTask = createInstallTask (); |
| } |
| return installTask; |
| } |
| |
| private RequestProcessor.Task createInstallTask () { |
| assert installTask == null || installTask.isFinished () : "The Install Task cannot be started nor scheduled."; |
| installTask = FeatureManager.getInstance().create(new InstallOrActivateTask(this)); |
| return installTask; |
| } |
| |
| final void installMissingModules () { |
| try { |
| doInstallMissingModules (); |
| } catch (Exception x) { |
| JButton tryAgain = new JButton (); |
| tryAgain.addActionListener(new ActionListener () { |
| public void actionPerformed (ActionEvent e) { |
| if (installContainer != null) { |
| try { |
| installContainer.getSupport ().doCancel (); |
| } catch (Exception ex) { |
| Logger.getLogger (ModulesInstaller.class.getName ()). |
| log (Level.INFO, ex.getLocalizedMessage (), ex); |
| } |
| } |
| RequestProcessor.Task task = getInstallTask (); |
| if (task != null) { |
| task.schedule (10); |
| } |
| } |
| }); |
| Logger.getLogger (ModulesInstaller.class.getName ()).log (Level.INFO, x.getLocalizedMessage (), x); |
| tryAgain.setEnabled (getInstallTask () != null); |
| Mnemonics.setLocalizedText (tryAgain, getBundle ("InstallerMissingModules_TryAgainButton")); |
| NotifyDescriptor nd = new NotifyDescriptor ( |
| getErrorNotifyPanel (x), |
| getBundle ("InstallerMissingModules_ErrorPanel_Title"), |
| NotifyDescriptor.DEFAULT_OPTION, |
| NotifyDescriptor.ERROR_MESSAGE, |
| new Object [] { tryAgain, NotifyDescriptor.OK_OPTION }, |
| NotifyDescriptor.OK_OPTION |
| ); |
| DialogDisplayer.getDefault ().notifyLater (nd); |
| } finally { |
| FoDLayersProvider.getInstance().refreshForce(); |
| } |
| } |
| |
| private JComponent getErrorNotifyPanel (Exception x) { |
| JTextArea area = new JTextArea (); |
| area.setWrapStyleWord (true); |
| area.setLineWrap (true); |
| area.setEditable (false); |
| area.setRows (15); |
| area.setColumns (40); |
| area.setOpaque (false); |
| area.setText (getBundle ("InstallerMissingModules_ErrorPanel", x.getLocalizedMessage (), x)); |
| return area; |
| } |
| |
| private void doInstallMissingModules () throws OperationException { |
| assert ! SwingUtilities.isEventDispatchThread () : "Cannot be called in EQ."; |
| installContainer = null; |
| for (UpdateElement module : modules4install) { |
| if (installContainer == null) { |
| boolean isNewOne = module.getUpdateUnit ().getInstalled () == null; |
| if (isNewOne) { |
| installContainer = OperationContainer.createForInstall (); |
| } else { |
| installContainer = OperationContainer.createForUpdate (); |
| } |
| } |
| if (installContainer.canBeAdded (module.getUpdateUnit (), module)) { |
| installContainer.add (module); |
| } |
| } |
| if (installContainer.listAll ().isEmpty ()) { |
| return ; |
| } |
| assert installContainer.listInvalid ().isEmpty () : |
| "No invalid Update Elements " + installContainer.listInvalid (); |
| if (! installContainer.listInvalid ().isEmpty ()) { |
| throw new IllegalArgumentException ("Some are invalid for install: " + installContainer.listInvalid ()); |
| } |
| boolean ok = PluginManager.openInstallWizard(installContainer); |
| if (!ok) { |
| StringBuilder sb = new StringBuilder(); |
| String sep = ""; |
| for (UpdateElement el : modules4install) { |
| sb.append(sep); |
| sb.append(el.getDisplayName()); |
| sep = ", "; |
| } |
| progressMonitor.onError( |
| getBundle("InstallerMissingModules_Cancelled", sb) // NOI18N |
| ); |
| } |
| } |
| |
| public static String presentUpdateElements (Collection<UpdateElement> elems) { |
| StringBuilder sb = new StringBuilder(); |
| String sep = ""; |
| Set<String> used = new HashSet<String>(); |
| |
| for (UpdateElement el : elems) { |
| if (!used.add(el.getCategory())) { |
| continue; |
| } |
| sb.append(sep); |
| sb.append(el.getCategory()); |
| if (sb.length() > 30) { |
| sb.append("..."); // NOI18N |
| break; |
| } |
| sep = ", "; // NOI18N |
| } |
| return sb.toString(); |
| } |
| |
| private void waitToModuleLoaded () { |
| assert ! SwingUtilities.isEventDispatchThread () : "Cannot be called in EQ."; |
| for (UpdateElement m : modules4install) { |
| while (!m.isEnabled()) { |
| try { |
| Thread.sleep(100); |
| } catch (InterruptedException ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| } |
| |
| } |
| |
| private static String getBundle (String key, Object... params) { |
| return NbBundle.getMessage (ModulesInstaller.class, key, params); |
| } |
| |
| } |