| // Copyright (C) 2013 The Android Open Source Project |
| // |
| // Licensed 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 com.google.gerrit.client.api; |
| |
| import com.google.gerrit.client.ErrorDialog; |
| import com.google.gerrit.client.Gerrit; |
| import com.google.gerrit.client.VoidResult; |
| import com.google.gerrit.client.rpc.NativeMap; |
| import com.google.gerrit.client.rpc.Natives; |
| import com.google.gwt.core.client.Callback; |
| import com.google.gwt.core.client.CodeDownloadException; |
| import com.google.gwt.core.client.ScriptInjector; |
| import com.google.gwt.user.client.Timer; |
| import com.google.gwt.user.client.Window; |
| import com.google.gwt.user.client.rpc.AsyncCallback; |
| import com.google.gwt.user.client.ui.DialogBox; |
| import com.google.gwtexpui.progress.client.ProgressBar; |
| import java.util.List; |
| import java.util.stream.Collectors; |
| |
| /** Loads JavaScript plugins with a progress meter visible. */ |
| public class PluginLoader extends DialogBox { |
| private static PluginLoader self; |
| |
| public static void load( |
| List<String> plugins, int loadTimeout, AsyncCallback<VoidResult> callback) { |
| if (plugins == null || plugins.isEmpty()) { |
| callback.onSuccess(VoidResult.create()); |
| } else { |
| plugins = plugins.stream().filter(p -> p.endsWith(".js")).collect(Collectors.toList()); |
| if (plugins.isEmpty()) { |
| callback.onSuccess(VoidResult.create()); |
| } else { |
| self = new PluginLoader(loadTimeout, callback); |
| self.load(plugins); |
| self.startTimers(); |
| self.center(); |
| } |
| } |
| } |
| |
| static void loaded() { |
| self.loadedOne(); |
| } |
| |
| private final int loadTimeout; |
| private final AsyncCallback<VoidResult> callback; |
| private ProgressBar progress; |
| private Timer show; |
| private Timer update; |
| private Timer timeout; |
| private boolean visible; |
| |
| private PluginLoader(int loadTimeout, AsyncCallback<VoidResult> cb) { |
| super(/* auto hide */ false, /* modal */ true); |
| callback = cb; |
| this.loadTimeout = loadTimeout; |
| progress = new ProgressBar(Gerrit.C.loadingPlugins()); |
| |
| setStyleName(Gerrit.RESOURCES.css().errorDialog()); |
| addStyleName(Gerrit.RESOURCES.css().loadingPluginsDialog()); |
| } |
| |
| private void load(List<String> pluginUrls) { |
| for (String url : pluginUrls) { |
| Plugin plugin = Plugin.create(url); |
| plugins().put(url, plugin); |
| ScriptInjector.fromUrl(url) |
| .setWindow(ScriptInjector.TOP_WINDOW) |
| .setCallback(new LoadCallback(plugin)) |
| .inject(); |
| } |
| } |
| |
| private void startTimers() { |
| show = |
| new Timer() { |
| @Override |
| public void run() { |
| setText(Window.getTitle()); |
| setWidget(progress); |
| setGlassEnabled(true); |
| getGlassElement().addClassName(Gerrit.RESOURCES.css().errorDialogGlass()); |
| hide(true); |
| center(); |
| visible = true; |
| } |
| }; |
| show.schedule(500); |
| |
| update = |
| new Timer() { |
| private int cycle; |
| |
| @Override |
| public void run() { |
| progress.setValue(100 * ++cycle * 250 / loadTimeout); |
| } |
| }; |
| update.scheduleRepeating(250); |
| |
| timeout = |
| new Timer() { |
| @Override |
| public void run() { |
| finish(); |
| } |
| }; |
| timeout.schedule(loadTimeout); |
| } |
| |
| private void loadedOne() { |
| boolean done = true; |
| for (Plugin plugin : Natives.asList(plugins().values())) { |
| done &= plugin.loaded(); |
| } |
| if (done) { |
| finish(); |
| } |
| } |
| |
| private void finish() { |
| show.cancel(); |
| update.cancel(); |
| timeout.cancel(); |
| self = null; |
| |
| if (!hadFailures()) { |
| if (visible) { |
| progress.setValue(100); |
| new Timer() { |
| @Override |
| public void run() { |
| hide(true); |
| } |
| }.schedule(250); |
| } else { |
| hide(true); |
| } |
| } |
| |
| callback.onSuccess(VoidResult.create()); |
| } |
| |
| private boolean hadFailures() { |
| boolean failed = false; |
| for (Plugin plugin : Natives.asList(plugins().values())) { |
| if (!plugin.success()) { |
| failed = true; |
| |
| Exception e = plugin.failure(); |
| String msg; |
| if (e != null && e instanceof CodeDownloadException) { |
| msg = Gerrit.M.cannotDownloadPlugin(plugin.url()); |
| } else { |
| msg = Gerrit.M.pluginFailed(plugin.name()); |
| } |
| hide(true); |
| new ErrorDialog(msg).center(); |
| } |
| } |
| return failed; |
| } |
| |
| private static native NativeMap<Plugin> plugins() /*-{ return $wnd.Gerrit.plugins }-*/; |
| |
| private class LoadCallback implements Callback<Void, Exception> { |
| private final Plugin plugin; |
| |
| LoadCallback(Plugin plugin) { |
| this.plugin = plugin; |
| } |
| |
| @Override |
| public void onSuccess(Void result) {} |
| |
| @Override |
| public void onFailure(Exception reason) { |
| plugin.failure(reason); |
| loadedOne(); |
| } |
| } |
| } |