ro.nextreports.server.web.dashboard.WidgetPopupMenuModel.java Source code

Java tutorial

Introduction

Here is the source code for ro.nextreports.server.web.dashboard.WidgetPopupMenuModel.java

Source

/*
 * 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 java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.AjaxSelfUpdatingTimerBehavior;
import org.apache.wicket.ajax.attributes.AjaxCallListener;
import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.injection.Injector;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.link.PopupSettings;
import org.apache.wicket.markup.html.link.ResourceLink;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.StringResourceModel;
import org.apache.wicket.request.resource.ByteArrayResource;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.apache.wicket.util.time.Duration;
import org.jfree.util.Log;

import ro.nextreports.server.domain.Chart;
import ro.nextreports.server.domain.Entity;
import ro.nextreports.server.domain.QueryRuntime;
import ro.nextreports.server.domain.Report;
import ro.nextreports.server.domain.UserWidgetParameters;
import ro.nextreports.server.exception.DuplicationException;
import ro.nextreports.server.exception.NotFoundException;
import ro.nextreports.server.service.DashboardService;
import ro.nextreports.server.service.DataSourceService;
import ro.nextreports.server.service.ReportService;
import ro.nextreports.server.service.SecurityService;
import ro.nextreports.server.service.StorageService;
import ro.nextreports.server.util.ChartUtil;
import ro.nextreports.server.util.PermissionUtil;
import ro.nextreports.server.util.ServerUtil;
import ro.nextreports.server.util.StorageUtil;
import ro.nextreports.server.util.WidgetUtil;
import ro.nextreports.server.web.NextServerSession;
import ro.nextreports.server.web.chart.ChartRuntimePanel;
import ro.nextreports.server.web.chart.ChartSection;
import ro.nextreports.server.web.common.menu.MenuItem;
import ro.nextreports.server.web.common.menu.MenuPanel;
import ro.nextreports.server.web.common.misc.AjaxConfirmLink;
import ro.nextreports.server.web.core.BasePage;
import ro.nextreports.server.web.core.HomePage;
import ro.nextreports.server.web.core.section.SectionContextUtil;
import ro.nextreports.server.web.core.section.SectionManager;
import ro.nextreports.server.web.dashboard.chart.ChartWidget;
import ro.nextreports.server.web.dashboard.drilldown.DrillDownWidget;
import ro.nextreports.server.web.dashboard.pivot.PivotResource;
import ro.nextreports.server.web.dashboard.pivot.PivotWidget;
import ro.nextreports.server.web.dashboard.table.GeneralWidgetRuntimePanel;
import ro.nextreports.server.web.dashboard.table.TableResource;
import ro.nextreports.server.web.dashboard.table.TableWidget;
import ro.nextreports.server.web.dashboard.table.TableWidgetRuntimePanel;
import ro.nextreports.server.web.report.DynamicParameterRuntimePanel;
import ro.nextreports.server.web.report.ParameterRuntimePanel;
import ro.nextreports.server.web.report.ReportSection;
import ro.nextreports.server.web.security.SecurityUtil;
import ro.nextreports.engine.util.ObjectCloner;

public class WidgetPopupMenuModel extends LoadableDetachableModel<List<MenuItem>> {

    private static final long serialVersionUID = 1L;

    public static final int POPUP_WIDTH = 700;
    public static final int POPUP_HEIGHT = 400;

    @SpringBean
    private StorageService storageService;

    @SpringBean
    private ReportService reportService;

    @SpringBean
    private DataSourceService dataSourceService;

    @SpringBean
    private SecurityService securityService;

    @SpringBean
    private DashboardService dashboardService;

    @SpringBean
    private SectionManager sectionManager;

    private IModel<Widget> model;

    public WidgetPopupMenuModel(IModel<Widget> model) {
        this.model = model;
    }

    @Override
    protected List<MenuItem> load() {
        Injector.get().inject(this);
        List<MenuItem> menuItems = new ArrayList<MenuItem>();
        menuItems.add(new MenuItem(createEditLink(model),
                new StringResourceModel("WidgetPopupMenu.editSettings", null).getString(), "images/edit.png"));
        if (model.getObject().saveToExcel()) {
            menuItems.add(new MenuItem(createSaveToExcelLink(model),
                    new StringResourceModel("WidgetPopupMenu.saveExcel", null).getString(), "images/excel.gif"));
        }
        menuItems.add(new MenuItem(createGoToLink(model),
                new StringResourceModel("WidgetPopupMenu.gotoEntity", null).getString(), "images/widget_go.png"));
        menuItems.add(new MenuItem(createRefreshLink(model),
                new StringResourceModel("WidgetPopupMenu.refresh", null).getString(), "images/refresh.gif"));
        menuItems.add(new MenuItem(createDetachLink(model),
                new StringResourceModel("WidgetPopupMenu.detach", null).getString(), "images/detach.png"));
        menuItems.add(new MenuItem(createEmbedCodeLink(model),
                new StringResourceModel("WidgetPopupMenu.embeddedCode", null).getString(),
                "images/embed_code.png"));
        menuItems.add(new MenuItem(createMoveLink(model),
                new StringResourceModel("WidgetPopupMenu.copyMove", null).getString(), "images/move_widget.png"));
        menuItems.add(new MenuItem(createDeleteLink(model),
                new StringResourceModel("WidgetPopupMenu.delete", null).getString(), "images/delete.gif"));
        MenuItem menuItem = new MenuItem("images/actions.png", null);
        menuItem.setMenuItems(menuItems);

        return Arrays.asList(menuItem);
    }

    private Link<TableResource> createSaveToExcelLink(final IModel<Widget> model) {
        ByteArrayResource download;
        if (model.getObject() instanceof PivotWidget) {
            PivotWidget pivotWidget = (PivotWidget) model.getObject();
            download = new PivotResource(pivotWidget);
        } else {
            download = new TableResource(model.getObject().getId());
        }
        ResourceLink resourceLink = new ResourceLink<TableResource>(MenuPanel.LINK_ID, download);
        // see busy-indicator.js
        // we do not want a busy indicator in this situation
        resourceLink.add(new AttributeAppender("class", new Model<String>("noBusyIndicator"), " "));
        return resourceLink;
    }

    private AjaxLink createEditLink(final IModel<Widget> model) {
        AjaxLink<Void> editLink = new AjaxLink<Void>(MenuPanel.LINK_ID) {

            @Override
            public void onClick(AjaxRequestTarget target) {

                final Widget widget = model.getObject();
                final ModalWindow dialog = findParent(BasePage.class).getDialog();

                dialog.setTitle(new StringResourceModel("WidgetPopupMenu.editSettings", null).getString());
                dialog.setUseInitialHeight(false);
                dialog.setOutputMarkupId(true);

                final WidgetRuntimeModel runtimeModel;
                final ParameterRuntimePanel paramRuntimePanel;

                final EntityWidget entityWidget = (EntityWidget) widget;

                String userDataPath = WidgetUtil.getUserWidgetParametersPath(ServerUtil.getUsername()) + "/"
                        + entityWidget.getId();
                UserWidgetParameters wp = null;
                try {
                    String dashboardId = getDashboardId(entityWidget.getId());
                    String owner = dashboardService.getDashboardOwner(dashboardId);
                    String user = ServerUtil.getUsername();
                    boolean isDashboardLink = !owner.equals(user);
                    boolean hasWrite = securityService.hasPermissionsById(user, PermissionUtil.getWrite(),
                            dashboardId);
                    if (isDashboardLink && !hasWrite) {
                        wp = (UserWidgetParameters) storageService.getEntity(userDataPath);
                    }
                } catch (NotFoundException e) {
                    // nothing to do
                    Log.info("There is no UserWidgetParameters for : " + userDataPath);
                    System.out.println("----> NOT FOUND");
                }
                final UserWidgetParameters fwp = wp;

                runtimeModel = ChartUtil.getRuntimeModel(storageService.getSettings(), entityWidget, reportService,
                        dataSourceService, true, fwp);
                if ((widget instanceof ChartWidget) || ((widget instanceof DrillDownWidget)
                        && (((DrillDownWidget) widget).getEntity() instanceof Chart))) {
                    Chart chart = (Chart) entityWidget.getEntity();
                    paramRuntimePanel = new ChartRuntimePanel("chartRuntimePanel", chart, runtimeModel);
                } else if ((widget instanceof TableWidget) || ((widget instanceof DrillDownWidget)
                        && (((DrillDownWidget) widget).getEntity() instanceof Report))) {
                    paramRuntimePanel = new TableWidgetRuntimePanel("chartRuntimePanel", entityWidget.getEntity(),
                            runtimeModel);
                } else {
                    paramRuntimePanel = new GeneralWidgetRuntimePanel("chartRuntimePanel", entityWidget.getEntity(),
                            runtimeModel);
                }

                boolean isDynamic = false;
                if (paramRuntimePanel instanceof DynamicParameterRuntimePanel) {
                    if (((DynamicParameterRuntimePanel) paramRuntimePanel).hasDynamicParameter()) {
                        isDynamic = true;
                    }
                }

                if (paramRuntimePanel.hasPalette()) {
                    if (isDynamic) {
                        dialog.setInitialWidth(720);
                    } else {
                        dialog.setInitialWidth(685);
                    }
                } else {
                    if (isDynamic) {
                        dialog.setInitialWidth(445);
                    } else {
                        dialog.setInitialWidth(435);
                    }
                }

                final Component component = this;

                dialog.setContent(new WidgetSettingsPanel(dialog.getContentId(), paramRuntimePanel) {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onChange(AjaxRequestTarget target) {
                        changeSettings(getFeedbackPanel(), component, widget, runtimeModel, target);
                    }

                    @Override
                    public void onCancel(AjaxRequestTarget target) {
                        ModalWindow.closeCurrent(target);
                    }

                    @Override
                    public void onReset(AjaxRequestTarget target) {
                        resetSettings(getFeedbackPanel(), component, widget, target);
                    }
                });

                dialog.show(target);
            }

            //         @Override
            //            public boolean isVisible() {            
            //            return hasWritePermission(model.getObject());
            //         }              
        };

        return editLink;
    }

    private void errorRefresh() {
        NextServerSession.get().error(new StringResourceModel("WidgetPopupMenu.error", null).getString());
    }

    private void changeSettings(FeedbackPanel feedbackPanel, Component component, Widget widget,
            WidgetRuntimeModel runtimeModel, AjaxRequestTarget target) {
        final WidgetPanel widgetPanel = component.findParent(WidgetPanel.class);
        int oldRefreshTime = widget.getRefreshTime();
        Map<String, String> widgetSettings = null;
        try {
            String dashboardId = getDashboardId(widget.getId());
            String owner = dashboardService.getDashboardOwner(dashboardId);
            String user = ServerUtil.getUsername();
            boolean isDashboardLink = !owner.equals(user);

            if (component.findParent(DashboardPanel.class) == null) {
                errorRefresh();
                target.add(feedbackPanel);
                return;
            } else {
                ModalWindow.closeCurrent(target);
            }

            boolean hasWrite = securityService.hasPermissionsById(user, PermissionUtil.getWrite(), dashboardId);
            if (isDashboardLink && !hasWrite) {
                // if dashboard is not owned by user (was shared to him)
                // save parameters values under usersData node if user has only read permission
                QueryRuntime newQueryRuntime = ChartUtil
                        .updateQueryRuntime(ObjectCloner.silenceDeepCopy(widget.getQueryRuntime()), runtimeModel);
                widgetSettings = ChartUtil.getSettingsFromModel(runtimeModel);
                String parentPath = WidgetUtil.getUserWidgetParametersPath(user);
                String path = parentPath + "/" + widget.getId();
                if (storageService.entityExists(path)) {
                    UserWidgetParameters wp = (UserWidgetParameters) storageService.getEntity(path);
                    oldRefreshTime = Integer.parseInt(wp.getSettings().get(ChartWidget.REFRESH_TIME));
                    wp.setQueryRuntime(newQueryRuntime);
                    wp.setSettings(widgetSettings);
                    storageService.modifyEntity(wp);
                } else {
                    UserWidgetParameters wp = new UserWidgetParameters(widget.getId(), path);
                    wp.setQueryRuntime(newQueryRuntime);
                    wp.setSettings(widgetSettings);
                    storageService.createFolders(parentPath);
                    storageService.addEntity(wp);
                }
                dashboardService.resetCache(widget.getId());
            } else {
                ChartUtil.updateWidget(widget, runtimeModel);
                dashboardService.modifyWidget(dashboardId, widget);
            }
        } catch (NotFoundException e) {
            // never happening
            throw new RuntimeException(e);
        } catch (DuplicationException e) {
            throw new RuntimeException(e);
        }
        int refreshTime = widget.getRefreshTime();
        if (widgetSettings != null) {
            refreshTime = Integer.parseInt(widgetSettings.get(ChartWidget.REFRESH_TIME));
        }
        if (oldRefreshTime != refreshTime) {
            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 ...
                }
            }
            if (refreshTime > 0) {
                widgetPanel.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(refreshTime)));
            }
        }
        if ((widget instanceof DrillDownWidget) || (widget instanceof PivotWidget)) {
            widgetPanel.refresh(target);
        } else {
            //target.add(widgetPanel);   
            // ChartRendererPanel uses container.replace("chart")
            // we should add widgetView again instead of a simple target.add(widgetPanel), otherwise we will see two refreshes
            widgetPanel.refresh(target);
        }
    }

    // return true if we reset settings for a dashboard link with UserWidgetParameters
    private void resetSettings(FeedbackPanel feedbackPanel, Component component, Widget widget,
            AjaxRequestTarget target) {
        // on reset settings we must delete UserWidgetParameters if any
        try {
            UserWidgetParameters wp = dashboardService.getUserWidgetParameters(widget.getId());
            if (wp != null) {
                storageService.removeEntityById(wp.getId());
                dashboardService.resetCache(widget.getId());
                final WidgetPanel widgetPanel = component.findParent(WidgetPanel.class);
                ModalWindow.closeCurrent(target);
                //target.add(widgetPanel);
                // ChartRendererPanel uses container.replace("chart")
                // we should add widgetView again instead of a simple target.add(widgetPanel), otherwise we will see two refreshes
                widgetPanel.refresh(target);
                return;
            }
        } catch (NotFoundException ex) {
            // should not happen
            Log.error(ex.getMessage(), ex);
        }
        if ((widget instanceof DrillDownWidget) && (((DrillDownWidget) widget).getEntity() instanceof Chart)) {
            final WidgetPanel widgetPanel = component.findParent(WidgetPanel.class);
            ChartUtil.updateWidget(widget, ChartUtil.getRuntimeModel(storageService.getSettings(),
                    (EntityWidget) widget, reportService, dataSourceService, false));
            try {
                if (component.findParent(DashboardPanel.class) == null) {
                    errorRefresh();
                    target.add(feedbackPanel);
                    return;
                } else {
                    ModalWindow.closeCurrent(target);
                }
                dashboardService.modifyWidget(getDashboardId(widget.getId()), widget);
            } catch (NotFoundException e) {
                // never happening
            }
            widgetPanel.refresh(target);
        } else if (widget instanceof ChartWidget) {
            final WidgetPanel widgetPanel = component.findParent(WidgetPanel.class);
            if (component.findParent(DashboardPanel.class) == null) {
                errorRefresh();
                target.add(feedbackPanel);
                return;
            } else {
                ModalWindow.closeCurrent(target);
            }
            ChartUtil.updateWidget(widget, ChartUtil.getDefaultRuntimeModel(storageService.getSettings(),
                    (ChartWidget) widget, reportService, dataSourceService));
            try {
                dashboardService.modifyWidget(getDashboardId(widget.getId()), widget);
            } catch (NotFoundException e) {
                // never happening
            }
            //target.add(widgetPanel);
            // ChartRendererPanel uses container.replace("chart")
            // we should add widgetView again instead of a simple target.add(widgetPanel), otherwise we will see two refreshes
            widgetPanel.refresh(target);
        }
    }

    private String getDashboardId(String widgetId) throws NotFoundException {
        return storageService.getDashboardId(widgetId);
    }

    private Link createGoToLink(final IModel<Widget> model) {
        Link<Void> link = new Link<Void>(MenuPanel.LINK_ID) {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick() {
                Widget widget = model.getObject();
                String sectionId = getSectionId();
                String entityId = widget.getInternalSettings().get(EntityWidget.ENTITY_ID);
                try {
                    Entity entity = storageService.getEntityById(entityId);
                    sectionManager.setSelectedSectionId(sectionId);
                    SectionContextUtil.setCurrentPath(sectionId, StorageUtil.getParentPath(entity.getPath()));
                    SectionContextUtil.setSelectedEntityPath(sectionId, entity.getPath());
                    setResponsePage(HomePage.class);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public boolean isVisible() {
                Widget widget = model.getObject();
                String sectionId = getSectionId();
                String entityId = widget.getInternalSettings().get(EntityWidget.ENTITY_ID);
                try {
                    Entity entity = storageService.getEntityById(entityId);
                    return securityService.hasPermissionsById(SecurityUtil.getLoggedUsername(),
                            PermissionUtil.getRead(), entityId);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return false;
            }

            private String getSectionId() {
                Widget widget = model.getObject();
                String sectionId;
                if (widget instanceof DrillDownWidget) {
                    if (((DrillDownWidget) widget).getEntity() instanceof Chart) {
                        sectionId = ChartSection.ID;
                    } else {
                        sectionId = ReportSection.ID;
                    }
                } else if (widget instanceof ChartWidget) {
                    sectionId = ChartSection.ID;
                } else {
                    sectionId = ReportSection.ID;
                }
                return sectionId;
            }

        };
        return link;
    }

    private AjaxLink createRefreshLink(final IModel<Widget> model) {

        AjaxLink<Void> refreshLink = new AjaxLink<Void>(MenuPanel.LINK_ID) {

            @Override
            public void onClick(AjaxRequestTarget target) {
                WidgetPanel widgetPanel = findParent(WidgetPanel.class);
                widgetPanel.refresh(target);
                WidgetView widgetView = widgetPanel.getWidgetView();
                target.add(widgetView);
            }
        };
        return refreshLink;
    }

    private Link createDetachLink(final IModel<Widget> model) {
        Link<Void> link = new Link<Void>(MenuPanel.LINK_ID) {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick() {
                setResponsePage(new WidgetZoomPage(model.getObject().getId()));
            }

        };

        // see busy-indicator.js
        // we do not want a busy indicator in this situation
        link.add(new AttributeAppender("class", new Model<String>("noBusyIndicator"), " "));

        PopupSettings popupSettings = new PopupSettings(PopupSettings.RESIZABLE | PopupSettings.SCROLLBARS);
        popupSettings.setWidth(POPUP_WIDTH).setHeight(POPUP_HEIGHT);
        link.setPopupSettings(popupSettings);
        return link;
    }

    private AjaxLink createEmbedCodeLink(final IModel<Widget> model) {
        AjaxLink<Void> link = new AjaxLink<Void>(MenuPanel.LINK_ID) {

            private static final long serialVersionUID = 1L;

            @Override
            public void onClick(AjaxRequestTarget target) {
                final Widget widget = model.getObject();
                ModalWindow dialog = findParent(BasePage.class).getDialog();

                dialog.setTitle(new StringResourceModel("WidgetPopupMenu.embeddedCode", null).getString());
                dialog.setInitialWidth(550);
                dialog.setUseInitialHeight(false);

                dialog.setContent(new WidgetEmbedCodePanel(dialog.getContentId(), widget.getId()));
                dialog.show(target);
            }
        };
        return link;
    }

    private AjaxLink createMoveLink(final IModel<Widget> model) {
        AjaxLink<Void> moveLink = new AjaxLink<Void>(MenuPanel.LINK_ID) {

            @Override
            public void onClick(AjaxRequestTarget target) {

                final Widget widget = model.getObject();
                ModalWindow dialog = findParent(BasePage.class).getDialog();

                dialog.setTitle(new StringResourceModel("WidgetPopupMenu.copyMoveWidget", null).getString());
                dialog.setInitialWidth(300);
                dialog.setUseInitialHeight(false);

                final Component component = this;

                dialog.setContent(new SelectDashboardPanel(dialog.getContentId()) {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onAction(String toDashboardId, boolean move, AjaxRequestTarget target) {
                        try {
                            int column = dashboardService.getWidgetColumn(widget.getId());
                            if (move) {
                                dashboardService.moveWidget(DashboardUtil.getSelectedDashboardId(), toDashboardId,
                                        widget.getId());
                                DashboardColumnPanel columnPanel = component.findParent(DashboardPanel.class)
                                        .getColumnPanel(column);
                                target.add(component.findParent(DashboardColumnPanel.class));
                                target.add(columnPanel);
                            } else {
                                dashboardService.copyWidget(DashboardUtil.getSelectedDashboardId(), toDashboardId,
                                        widget.getId());
                            }
                        } catch (NotFoundException e) {
                            e.printStackTrace();
                            // should never happen
                        } finally {
                            ModalWindow.closeCurrent(target);
                        }
                    }

                    @Override
                    public void onCancel(AjaxRequestTarget target) {
                        ModalWindow.closeCurrent(target);
                    }
                });

                dialog.show(target);
            }

            @Override
            public boolean isVisible() {
                return hasWritePermission(model.getObject());
            }
        };
        return moveLink;
    }

    private AjaxConfirmLink createDeleteLink(final IModel<Widget> model) {
        AjaxConfirmLink<Void> deleteLink = new AjaxConfirmLink<Void>(MenuPanel.LINK_ID,
                new StringResourceModel("WidgetPopupMenu.deleteWidget", null).getString() + " "
                        + model.getObject().getTitle() + "?") {

            @Override
            public void onClick(AjaxRequestTarget target) {
                int column = dashboardService.getWidgetColumn(model.getObject().getId());
                try {
                    dashboardService.removeWidget(getDashboardId(model.getObject().getId()),
                            model.getObject().getId());
                } catch (NotFoundException e) {
                    // never happening
                    throw new RuntimeException(e);
                }
                // the widget is removed with javascript (with a IAjaxCallDecorator) -> see getAjaxCallDecorator()

                // dashboard may become empty (hide global settings)
                findParent(DashboardPanel.class).refreshGlobalSettings(target);
            }

            @Override
            public boolean isVisible() {
                return hasWritePermission(model.getObject());
            }

            @Override
            protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
                super.updateAjaxAttributes(attributes);

                attributes.getAjaxCallListeners().add(new AjaxCallListener() {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public CharSequence getSuccessHandler(Component component) {
                        return "$('#widget-" + model.getObject().getId() + "').remove();";
                    }

                });
            }

        };

        return deleteLink;
    }

    private boolean hasWritePermission(Widget widget) {
        try {
            return securityService.hasPermissionsById(ServerUtil.getUsername(), PermissionUtil.getWrite(),
                    getDashboardId(widget.getId()));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

}