/** * Copyright 2012 Universitat Pompeu Fabra. * * 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 org.onexus.ui.api.progressbar; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortState; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; import org.apache.wicket.extensions.markup.html.repeater.tree.DefaultTableTree; import org.apache.wicket.extensions.markup.html.repeater.tree.ISortableTreeProvider; import org.apache.wicket.extensions.markup.html.repeater.tree.table.TreeColumn; import org.apache.wicket.extensions.markup.html.repeater.util.SingleSortState; import org.apache.wicket.markup.head.CssHeaderItem; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.panel.EmptyPanel; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.AbstractReadOnlyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.request.cycle.RequestCycle; import org.apache.wicket.request.resource.PackageResourceReference; import org.onexus.resource.api.IProgressManager; import org.onexus.resource.api.IProgressable; import org.onexus.resource.api.Progress; import org.onexus.ui.api.progressbar.columns.LogsColumn; import org.onexus.ui.api.progressbar.columns.StatusColumn; import javax.inject.Inject; import javax.inject.Named; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; public class ProgressBar extends Panel { public static final PackageResourceReference CSS = new PackageResourceReference(ProgressBar.class, "ProgressBar.css"); private List<IColumn<Progress, String>> columns; private ProgressTreeProvider provider; private ProgressExpansionModel treeState; @Inject private IProgressManager progressManager; public ProgressBar(String id) { super(id); provider = new ProgressTreeProvider(); treeState = new ProgressExpansionModel(); setOutputMarkupId(true); final WebMarkupContainer modal = new WebMarkupContainer("modal") { @Override protected void onBeforeRender() { addOrReplace(new DefaultTableTree<Progress, String>("tree", columns, provider, Integer.MAX_VALUE, treeState).setOutputMarkupId(true)); super.onBeforeRender(); } }; final WebMarkupContainer minimized = new WebMarkupContainer("minimized"); minimized.setOutputMarkupId(true); add(minimized); final WebMarkupContainer logDetails = new WebMarkupContainer("log-details"); logDetails.setOutputMarkupId(true); logDetails.add(new EmptyPanel("logs")); modal.add(logDetails); modal.add(new AjaxLink<String>("refresh") { @Override public void onClick(AjaxRequestTarget target) { target.add(modal.get("tree")); } }); modal.setMarkupId("taskmanagerModal"); add(modal); minimized.add(new AjaxLink<String>("show") { @Override public void onClick(AjaxRequestTarget target) { target.add(modal); target.add(minimized); target.appendJavaScript("$('#taskmanagerModal').modal('show')"); } }); this.columns = new ArrayList<IColumn<Progress, String>>(); columns.add(new TreeColumn<Progress, String>(Model.of("task"))); columns.add(new PropertyColumn<Progress, String>(Model.of("title"), "title")); columns.add(new StatusColumn()); columns.add(new LogsColumn() { @Override protected void showLogs(Progress progress, AjaxRequestTarget target) { logDetails.addOrReplace(new Label("logs", toLogsString(progress))); target.add(logDetails); } }); } private static SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MMM/dd HH:mm:ss"); private static String toLogsString(Progress progress) { StringBuilder str = new StringBuilder(); for (Progress.LogMsg msg : progress.getLogs()) { str.append(" [").append(msg.getType()).append("] "); str.append(formatter.format(msg.getTime())).append(" - "); str.append(msg.getMessage()); str.append('\n'); } return str.toString(); } @Override public void renderHead(IHeaderResponse response) { super.renderHead(response); response.render(CssHeaderItem.forReference(CSS)); } private class ProgressTreeProvider implements ISortableTreeProvider<Progress, String> { @Override public Iterator<? extends Progress> getRoots() { Collection<Progress> progresses = progressManager.getProgresses(); List<Progress> orderProgresses = new ArrayList<Progress>(progresses); Collections.sort(orderProgresses, new Comparator<Progress>() { @Override public int compare(Progress o1, Progress o2) { boolean d1 = o1.isDone(); boolean d2 = o2.isDone(); if (d1 && !d2) { return 1; } if (!d1 && d2) { return -1; } if (!d1 && !d2) { if (o1.getStatus() == Progress.Status.RUNNING) { return -1; } if (o2.getStatus() == Progress.Status.RUNNING) { return 1; } } return 0; } }); return orderProgresses.iterator(); } @Override public boolean hasChildren(Progress node) { return !node.getSubProgresses().isEmpty(); } @Override public Iterator<? extends Progress> getChildren(Progress node) { return node.getSubProgresses().iterator(); } @Override public IModel<Progress> model(Progress object) { return new Model<Progress>(object); } @Override public void detach() { } @Override public ISortState<String> getSortState() { return new SingleSortState<String>(); } } public static <T extends IProgressable> T show(T progressable) { Progress progress = progressable.getProgress(); if (progress != null) { AjaxRequestTarget target = RequestCycle.get().find(AjaxRequestTarget.class); if (target != null) { target.appendJavaScript("$('#taskmanagerModal').modal('show')"); } } return progressable; } private class ProgressExpansionModel extends AbstractReadOnlyModel<Set<Progress>> { @Override public Set<Progress> getObject() { return ProgressExpansion.get(); } } public static class ActiveProgress implements Serializable { private Map<String, Progress> progresses = new HashMap<String, Progress>(); public void addTask(Progress progress) { progresses.put(progress.getId(), progress); } public boolean isActive() { boolean res = false; for (Progress progress : getProgresses()) { if (!progress.isDone()) { res = true; break; } } return res; } public Collection<Progress> getProgresses() { return progresses.values(); } } }