PrintPreviewView.java

/*
** Module   : PrintPreviewView.java
** Abstract : PrintPreviewView defines UI to work with print preview.
**
** Copyright (c) 2017-2022, Golden Code Development Corporation.
**
** -#- -I- --Date-- ----------------Description----------------------
** 001 SBI 20170601 Created initial version.
** 002 TJD 20220331 Removed deprecated reference to Inputdialog.showFilterDialog()
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
** 
** Additional terms under GNU Affero GPL version 3 section 7:
** 
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
**   terms apply to the works covered under the License.  These additional terms
**   are non-permissive additional terms allowed under Section 7 of the GNU
**   Affero GPL version 3 and may not be removed by you.
** 
**   0. Attribution Requirement.
** 
**     You must preserve all legal notices or author attributions in the covered
**     work or Appropriate Legal Notices displayed by works containing the covered
**     work.  You may not remove from the covered work any author or developer
**     credit already included within the covered work.
** 
**   1. No License To Use Trademarks.
** 
**     This license does not grant any license or rights to use the trademarks
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
**     of Golden Code Development Corporation. You are not authorized to use the
**     name Golden Code, FWD, or the names of any author or contributor, for
**     publicity purposes without written authorization.
** 
**   2. No Misrepresentation of Affiliation.
** 
**     You may not represent yourself as Golden Code Development Corporation or FWD.
** 
**     You may not represent yourself for publicity purposes as associated with
**     Golden Code Development Corporation, FWD, or any author or contributor to
**     the covered work, without written authorization.
** 
**   3. No Misrepresentation of Source or Origin.
** 
**     You may not represent the covered work as solely your work.  All modified
**     versions of the covered work must be marked in a reasonable way to make it
**     clear that the modified work is not originating from Golden Code Development
**     Corporation or FWD.  All modified versions must contain the notices of
**     attribution required in this license.
*/


package com.goldencode.p2j.admin.client.application.home.print;

import java.util.List;

import org.gwtbootstrap3.client.ui.Button;
import org.gwtbootstrap3.client.ui.CheckBox;
import org.gwtbootstrap3.client.ui.Heading;
import org.gwtbootstrap3.client.ui.ListBox;

import com.goldencode.p2j.admin.client.application.home.BaseViewWithUiHandlers;
import com.goldencode.p2j.admin.client.widget.dialog.InputDialog;
import com.goldencode.p2j.admin.shared.PaperFormat;
import com.goldencode.p2j.admin.shared.PaperOrientation;
import com.goldencode.p2j.admin.shared.ReportPreview;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.ImageCell;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.Range;
import com.google.gwt.view.client.RangeChangeEvent;
import com.google.inject.Inject;
import com.google.inject.Provider;


/**
 * PrintPreviewView defines UI to work with print preview.
 */
public class PrintPreviewView
extends BaseViewWithUiHandlers<PrintPreviewUiHandlers>
implements PrintPreviewPresenter.MyView
{
   /**
    * GWT UI creator.
    */
   interface Binder
   extends UiBinder<Widget, PrintPreviewView>
   {}
   
   /** The heading widget that holds the preview title */
   @UiField
   Heading previewTitle;
   
   /** The preview container */
   @UiField
   ScrollPanel previewContainer;
   
   /** The page lock forbids the preview pager to move over report pages */
   private boolean pageLock;
   
   /** The preview pager */
   @UiField(provided = true)
   PreviewPager pager = new PreviewPager();
   
   /**
    * Implements the report preview pager.
    */
   class PreviewPager
   extends SimplePager
   {
      /**
       * Returns true if there is enough data such that a call to {@link #nextPage()} will succeed
       * in moving the starting point of the table forward.
       *
       * @return   True if there is a next page
       */
      @Override
      public boolean hasNextPage()
      {
         return !pageLock && super.hasNextPage();
      }

      /**
       * Returns true if there is enough data to display a given number of additional pages.
       *
       * @param    pages
       *           The number of pages to query
       * 
       * @return   True if there are {@code pages} next pages
       */
     @Override
      public boolean hasNextPages(int pages)
      {
         return !pageLock && super.hasNextPages(pages);
      }

     /**
      * Returns true if there is enough data such that a call to {@link #previousPage()} will
      * succeed in moving the starting point of the table backward.
      *
      * @return   True if there is a previous page
      */
      @Override
      public boolean hasPreviousPage()
      {
         return !pageLock && super.hasPreviousPage();
      }

      /**
       * Returns true if there is enough data to display a given number of previous pages.
       *
       * @param    pages
       *           The number of previous pages to query
       * 
       * @return   True if there are {@code pages} previous pages
       */
      @Override
      public boolean hasPreviousPages(int pages)
      {
         return !pageLock && super.hasPreviousPages(pages);
      }
      
      /**
       * Refreshes the current preview content.
       */
      public void refresh()
      {
         setDisplay(getDisplay());
      }
   };
   
   /** The paper format list box */
   @UiField
   ListBox paperFormat;
   
   /** The paper orientation list box */
   @UiField
   ListBox paperOrient;
   
   /**
    * Implements the print preview widget.
    */
   class PrintPreview extends CellList<String>
   {
      /**
       * Creates the print preview widget to display the given renderable object.
       * 
       * @param    cell
       *           The given cell object represented by the html img.
       */
      public PrintPreview(Cell<String> cell)
      {
         super(cell);
      }
      
      /**
       * Clears the preview content.
       */
      public void clearContent()
      {
         getChildContainer().removeAllChildren();
      }
   }
   
   /** The print preview widget to display the list of the report preview images */
   @UiField(provided = true)
   PrintPreview previewContent = new PrintPreview(
   /** 
    * Implements the preview cell to display the report preview image.
    */
   new ImageCell()
   {
      /**
       * Builds its cell html content for the given cell value.
       * 
       * @param    context
       *           The provided context that persists over its cells
       * @param    value
       *           The given cell value
       * @param    sb
       *           The safe html builder
       */
      @Override
      public void render(Context context, String value, SafeHtmlBuilder sb)
      {
         StringBuilder html = new StringBuilder().append("<img src='").append(value).append("'")
                  .append(" class='img-responsive' />");
         sb.appendHtmlConstant(html.toString());
      }
   });
   
   /** The report preview pages range */
   private Range range;
   
   /** The preview data provider */
   AsyncDataProvider<String> provider = new AsyncDataProvider<String>()
   {
      @Override
      protected void onRangeChanged(HasData<String> display)
      {
         range = display.getVisibleRange();
         logger.info("provider.onRangeChanged: start=" + range.getStart() +
                  ", length=" + range.getLength());
         if (getUiHandlers() != null)
         {
            getUiHandlers().updatePreview(display.getVisibleRange());
         }
      }
   };
   
   /** The Display All Details check box */
   @UiField
   CheckBox displayAllDetails;
   
   /** The Print button */
   @UiField
   Button printAction;
   
   /** The Download button */
   @UiField
   Button downloadAction;
   
   /** The Filter button */
   @UiField
   Button filterAction;
   
   /** The Cancel button */
   @UiField
   Button cancelAction;

   /** The modal container */
   @UiField
   HasWidgets modalFragment;
   
   /** The common input dialogs provider */
   private final Provider<InputDialog> inputDialogProvider;
   
   /**
    * Constructs this view, used by MPV gwtplatform of ArcBees Inc.
    * 
    * @param    binder
    *           The injected GWT UI creator
    * @param    inputDialogProvider
    *           The injected common input dialogs provider
    */
   @Inject
   public PrintPreviewView(Binder binder, Provider<InputDialog> inputDialogProvider)
   {
      this.inputDialogProvider = inputDialogProvider;
      initWidget(binder.createAndBindUi(this));
      previewContent.setPageSize(1);
      pager.setPageSize(1);
      pager.setDisplay(previewContent);
      previewContent.addRangeChangeHandler(new RangeChangeEvent.Handler()
      {
         
         @Override
         public void onRangeChange(RangeChangeEvent event)
         {
            pageLock = true;
            logger.info("previewContent.onRangeChange: start=" + event.getNewRange().getStart() +
                     ", length=" + event.getNewRange().getLength());
         }
      });
      filterAction.setEnabled(false);
      printAction.setEnabled(false);
      downloadAction.setEnabled(false);
      bindSlot(PrintPreviewPresenter.MODAL_CONTENT, modalFragment);
      paperFormat.addChangeHandler(new ChangeHandler()
      {
         @Override
         public void onChange(ChangeEvent event)
         {
            PaperFormat format = PaperFormat.valueOf(paperFormat.getSelectedValue());
            PaperOrientation orient = PaperOrientation.valueOf(paperOrient.getSelectedValue());
            
            logger.info("paperFormat.onChange: format=" + format + ", orient=" + orient);
            
            getUiHandlers().setNewPrintSettings(format, orient);
         }
      });
      paperOrient.addChangeHandler(new ChangeHandler()
      {
         @Override
         public void onChange(ChangeEvent event)
         {
            PaperFormat format = PaperFormat.valueOf(paperFormat.getSelectedValue());
            PaperOrientation orient = PaperOrientation.valueOf(paperOrient.getSelectedValue());
            
            logger.info("paperOrient.onChange: format=" + format + ", orient=" + orient);
            
            getUiHandlers().setNewPrintSettings(format, orient);
         }
      });
      displayAllDetails.addChangeHandler(new ChangeHandler()
      {
         
         @Override
         public void onChange(ChangeEvent event)
         {
            getUiHandlers().displayAllDetails(displayAllDetails.getValue());
         }
      });
   }

   /**
    * Sets the preview title.
    * 
    * @param    title
    *           The title text
    */
   @Override
   public void setPreviewTitle(String title)
   {
      this.previewTitle.setText(title);
      this.previewTitle.setTitle(title);
   }
   
   /**
    * Implements {@code Consumer<ReportPreview>} interface.
    * 
    * @param    reportPreview
    *           The report preview data transfer object
    */
   @Override
   public void accept(ReportPreview reportPreview)
   {
      pageLock = false;
      
      List<String> previewPages = reportPreview.getPreviewPages();
      logger.info("accept pages: " + previewPages.size());
      previewContent.setRowCount(reportPreview.getPagesNumber(), true);
      
      provider.updateRowData(range.getStart(), previewPages);
      
      filterAction.setEnabled(!previewPages.isEmpty());
      printAction.setEnabled(!previewPages.isEmpty());
      downloadAction.setEnabled(!previewPages.isEmpty());
      
      if (previewContainer.getWidget() == null)
      {
         previewContainer.add(previewContent);
      }
      
      pager.refresh();
   }

   /**
    * This is called when presenter has all the information to render the preview.
    */
   @Override
   public void onReportReady()
   {
      logger.info("onReportReady");
      provider.addDataDisplay(previewContent);
      pager.setDisplay(previewContent);
   }

   /**
    * The Print button click handler.
    * 
    * @param    event
    *           Click event
    */
   @UiHandler("printAction")
   void onPrintAction(ClickEvent event)
   {
      getUiHandlers().printReport();
   }
   
   /**
    * The Download button click handler.
    * 
    * @param    event
    *           Click event
    */
   @UiHandler("downloadAction")
   void onDownloadAction(ClickEvent event)
   {
      getUiHandlers().downloadReport();
   }
   
   /**
    * The Filter button click handler.
    * 
    * @param    event
    *           Click event
    */
   @UiHandler("filterAction")
   void onFilterAction(ClickEvent event)
   {
      InputDialog.Field newFilter;
      InputDialog inputDialog = this.inputDialogProvider.get();
      String hlpText = "<h4>Define the filtering specification below. Press the&nbsp;" +
               "'OK' button without any specification to remove any&nbsp;" +
               "previous filter.</h4>";
      inputDialog.build("Filter", hlpText , new InputDialog.Field[]
      {
         newFilter = new InputDialog.Field("Filter", getUiHandlers().getCurrentFilter(), true)
      });
      inputDialog.show(modalFragment, true, values ->
      {
         if (values != null)
         {
            String newFilterValue = (String) values.get(newFilter);
            getUiHandlers().setDataSelectionFilter(newFilterValue);
            logger.info("inputDialog -> " + newFilterValue);
         }
      });
   }

   /**
    * Gets the current preview range that is defined by the start page and the page count.
    * 
    * @return   The current preview range
    */
   @Override
   public Range getCurrentRange()
   {
      return range;
   }
   
   /**
    * The Cancel button click handler.
    * 
    * @param    event
    *           Click event
    */
   @UiHandler("cancelAction")
   void onCancelAction(ClickEvent event)
   {
      getUiHandlers().cancel();
   }

   /**
    * The view callback method that is invoked by its presenter executing onHide()
    * lifecycle method. 
    */
   @Override
   public void onHide()
   {
      logger.info("onHide: clear preview");
      provider.removeDataDisplay(previewContent);
      previewContainer.clear();
      previewContent.clearContent();
      previewContent.setRowCount(0, true);
      pager.setPageStart(0);
      pager.setDisplay(null);
   }

   /**
    * Sets the requested paper format. The server supports the paper format defined by
    * PaperFormat enumeration.
    * 
    * @param    value
    *           The paper format string
    */
   @Override
   public void setPaperFormat(String value)
   {
      selectValue(paperFormat, value);
   }

   /**
    * Finds the given value in the target list box and requests to select the corresponding list
    * item.
    * 
    * @param    list
    *           The target list box
    * @param    value
    *           The given value
    */
   private void selectValue(ListBox list, String value)
   {
      for( int i = list.getItemCount() - 1; i >=0; i--)
      {
         String itemValue = list.getValue(i);
         if (itemValue != null && itemValue.equals(value))
         {
            list.setItemSelected(i, true);
            break;
         }
      }
   }

   /**
    * Sets the requested paper orientation. The server supports the paper orientation defined
    * by PaperOrientation enumeration.
    * 
    * @param    value
    *           The paper orientation well-known string, LANDSCAPE or PORTRAIT.
    */
   @Override
   public void setPaperOrientation(String value)
   {
      selectValue(paperOrient, value);
   }

   /**
    * Requests the extended detailed report or the short form report.
    * 
    * @param    b
    *           The true value means to display the extended detailed report, otherwise
    *           the short form report.
    */
   @Override
   public void checkDisplayDetails(boolean b)
   {
      displayAllDetails.setValue(b, false);
   }

   /**
    * Shows or hides the Display All Details check box.
    * 
    * @param    visible
    *           The boolean value that defines the visibility of the Display All Details
    *           check box
    */
   @Override
   public void setDisplayDetailsVisible(boolean visible)
   {
      displayAllDetails.setVisible(visible);
   }
}