# 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);
       }
    }