/* * 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 ro.nextreports.server.web.dashboard; import org.apache.wicket.AttributeModifier; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.AjaxSelfUpdatingTimerBehavior; import org.apache.wicket.behavior.Behavior; import org.apache.wicket.extensions.ajax.markup.html.AjaxEditableLabel; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.image.ContextImage; import org.apache.wicket.markup.html.panel.GenericPanel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; import org.apache.wicket.spring.injection.annot.SpringBean; import org.apache.wicket.util.time.Duration; import org.odlabs.wiquery.core.events.Event; import org.odlabs.wiquery.core.events.MouseEvent; import org.odlabs.wiquery.core.events.WiQueryAjaxEventBehavior; import org.odlabs.wiquery.core.events.WiQueryEventBehavior; import org.odlabs.wiquery.core.javascript.JsScope; import org.odlabs.wiquery.core.javascript.JsStatement; import ro.nextreports.server.exception.NotFoundException; import ro.nextreports.server.service.DashboardService; import ro.nextreports.server.service.SecurityService; import ro.nextreports.server.service.StorageService; import ro.nextreports.server.util.PermissionUtil; import ro.nextreports.server.util.ServerUtil; /** * @author Decebal Suiu */ class WidgetHeaderPanel extends GenericPanel<Widget> { private static final long serialVersionUID = 1L; @SpringBean private DashboardService dashboardService; @SpringBean private SecurityService securityService; @SpringBean private StorageService storageService; private Label refreshLabel; public WidgetHeaderPanel(String id, final IModel<Widget> model) { super(id, model); IModel<String> toggleImageModel = new LoadableDetachableModel<String>() { private static final long serialVersionUID = 1L; @Override protected String load() { String imagePath = "images/down-gray.png"; if (getWidget().isCollapsed()) { imagePath = "images/up-gray.png"; } return imagePath; } }; ContextImage toggle = new ContextImage("toggle", toggleImageModel) { private static final long serialVersionUID = 1L; @Override public boolean isVisible() { DashboardPanel dashboardPanel = findParent(DashboardPanel.class); // in case of moving last widget from a dashboard, dashboardPanel is null if (dashboardPanel == null) { return false; } return dashboardPanel.hasWritePermission(); } }; toggle.add(new WiQueryEventBehavior(new Event(MouseEvent.CLICK) { private static final long serialVersionUID = 1L; @Override public JsScope callback() { return JsScope.quickScope(getJsCode()); } String collapse = getString("collapse"); String expand = getString("expand"); private CharSequence getJsCode() { /* var content = $(this).parent().siblings('.dragbox-content'); if (content.css('display') == 'none') { content.slideDown(400); $(this).attr("src", "../images/down.png"); $(this).attr('title', "Collapse"); } else { content.slideUp(200); $(this).attr('src', "../images/up.png"); $(this).attr('title', "Expand"); } */ StringBuilder buffer = new StringBuilder(); buffer.append("var content = $(this).parent().siblings('.dragbox-content');"); buffer.append("if (content.css('display') == 'none') {"); buffer.append("content.slideDown(400);"); buffer.append("$(this).attr('src', \"../images/down-gray.png\");"); buffer.append("$(this).attr('title', \"" + collapse + "\");"); buffer.append("} else {"); buffer.append("content.slideUp(200);"); buffer.append("$(this).attr('src', \"../images/up-gray.png\");"); buffer.append("$(this).attr('title', \"" + expand + "\");"); buffer.append("}"); return buffer.toString(); } })); toggle.add(new WiQueryAjaxEventBehavior(MouseEvent.CLICK) { private static final long serialVersionUID = 1L; @Override protected void onEvent(AjaxRequestTarget target) { Widget widget = getWidget(); widget.setCollapsed(!widget.isCollapsed()); DashboardPanel dashboardPanel = findParent(DashboardPanel.class); String dashboardId = dashboardPanel.getDashboard().getId(); try { dashboardService.modifyWidget(dashboardId, widget); } catch (NotFoundException e) { // never happening throw new RuntimeException(e); } // when collapse / uncollapse we must also look for AjaxSelfUpdatingTimerBehavior // to stop or start it if (!widget.isCollapsed()) { WidgetPanel widgetPanel = findParent(WidgetPanel.class); int refreshTime = model.getObject().getRefreshTime(); if (refreshTime > 0) { widgetPanel.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(refreshTime))); } widgetPanel.refresh(target); } else { WidgetPanel widgetPanel = findParent(WidgetPanel.class); for (Behavior behavior : widgetPanel.getBehaviors()) { if (behavior instanceof AjaxSelfUpdatingTimerBehavior) { ((AjaxSelfUpdatingTimerBehavior) behavior).stop(target); // do not remove the behavior : after changing , the event is called one more time // on the client so it has to be present ... } } } target.add(refreshLabel); } @Override public JsStatement statement() { return null; } }); IModel<String> toggleTooltipModel = new LoadableDetachableModel<String>() { private static final long serialVersionUID = 1L; @Override protected String load() { String tooltip = getString("collapse"); if (getWidget().isCollapsed()) { tooltip = getString("expand"); } return tooltip; } }; toggle.add(new AttributeModifier("title", toggleTooltipModel)); add(toggle); refreshLabel = new Label("refreshLabel", new LoadableDetachableModel<String>() { private static final long serialVersionUID = 1L; @Override protected String load() { String result = ""; if (!getWidget().isCollapsed()) { int refreshTime = model.getObject().getRefreshTime(); if (refreshTime > 0) { result = getFormattedRefreshTime(refreshTime); } } return result; } }); refreshLabel.setOutputMarkupId(true); add(refreshLabel); if (hasWritePermission(model.getObject())) { AjaxEditableLabel<String> titleLabel = new AjaxEditableLabel<String>("title", new Model<String>(model.getObject().getTitle())) { private static final long serialVersionUID = 1L; @Override protected void onModelChanged() { super.onModelChanged(); Widget widget = getWidget(); String title = (String) getDefaultModel().getObject(); if (title == null) { title = "No Title"; setDefaultModel(new Model<String>(title)); } else if (title.length() > 35) { title = title.substring(0, 35); setDefaultModel(new Model<String>(title)); } widget.setTitle(title); DashboardPanel dashboardPanel = findParent(DashboardPanel.class); String dashboardId = dashboardPanel.getDashboard().getId(); try { dashboardService.modifyWidget(dashboardId, widget); } catch (NotFoundException e) { // never happening throw new RuntimeException(e); } } }; add(titleLabel); } else { Label titleLabel = new Label("title", new Model<String>(model.getObject().getTitle())); add(titleLabel); } WidgetActionsPanel actionsPanel = new WidgetActionsPanel("actions", model); add(actionsPanel); // add(new WiQueryEventBehavior(new Event(MouseEvent.MOUSEOVER) { // // private static final long serialVersionUID = 1L; // // @Override // public JsScope callback() { // return JsScope.quickScope("$(this).find('.table-actions').show()"); // } // // })); // add(new WiQueryEventBehavior(new Event(MouseEvent.MOUSEOUT) { // // private static final long serialVersionUID = 1L; // // @Override // public JsScope callback() { // return JsScope.quickScope("$(this).find('.table-actions').hide()"); // } // // })); } public Widget getWidget() { return (Widget) getModelObject(); } private boolean hasWritePermission(Widget widget) { try { String dashboardId = storageService.getDashboardId(widget.getId()); return securityService.hasPermissionsById(ServerUtil.getUsername(), PermissionUtil.getWrite(), dashboardId); } catch (Exception e) { e.printStackTrace(); } return false; } private String getFormattedRefreshTime(int seconds) { StringBuilder sb = new StringBuilder(); if (seconds < 60) { sb.append(seconds).append(" (s)"); } else if (seconds < 3600) { int minutes = seconds / 60; int secs = seconds % 60; sb.append(minutes).append(" (m)"); if (secs > 0) { sb.append(" ").append(secs).append(" (s)"); } } else { int hours = seconds / 3600; int minsec = seconds % 3600; int minutes = minsec / 60; int secs = minsec % 60; sb.append(hours).append(" (h)"); if (minutes > 0) { sb.append(" ").append(minutes).append(" (m)"); } if (secs > 0) { sb.append(" ").append(secs).append(" (s)"); } } return sb.toString(); } }