BallotOverviewPageModContentFactoryImpl.java

  1. /*
  2.  * Copyright 2010-2025 James Pether Sörling
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *   http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  *
  16.  *  $Id$
  17.  *  $HeadURL$
  18. */
  19. package com.hack23.cia.web.impl.ui.application.views.user.ballot.pagemode;

  20. import java.util.List;

  21. import org.springframework.security.access.annotation.Secured;
  22. import org.springframework.stereotype.Component;

  23. import com.hack23.cia.model.internal.application.data.committee.impl.RiksdagenVoteDataBallotPartyEmbeddedId;
  24. import com.hack23.cia.model.internal.application.data.committee.impl.RiksdagenVoteDataBallotPartyEmbeddedId_;
  25. import com.hack23.cia.model.internal.application.data.committee.impl.ViewRiksdagenCommitteeBallotDecisionEmbeddedId;
  26. import com.hack23.cia.model.internal.application.data.committee.impl.ViewRiksdagenCommitteeBallotDecisionSummary;
  27. import com.hack23.cia.model.internal.application.data.committee.impl.ViewRiksdagenCommitteeBallotDecisionSummary_;
  28. import com.hack23.cia.model.internal.application.data.committee.impl.ViewRiksdagenVoteDataBallotPartySummary;
  29. import com.hack23.cia.model.internal.application.data.committee.impl.ViewRiksdagenVoteDataBallotPartySummary_;
  30. import com.hack23.cia.model.internal.application.data.committee.impl.ViewRiksdagenVoteDataBallotSummary;
  31. import com.hack23.cia.model.internal.application.system.impl.ApplicationEventGroup;
  32. import com.hack23.cia.service.api.DataContainer;
  33. import com.hack23.cia.web.impl.ui.application.action.ViewAction;
  34. import com.hack23.cia.web.impl.ui.application.views.common.menufactory.api.pagecommands.PageCommandBallotConstants;
  35. import com.hack23.cia.web.impl.ui.application.views.common.pagemode.CardInfoRowUtil;
  36. import com.hack23.cia.web.impl.ui.application.views.common.sizing.ContentRatio;
  37. import com.hack23.cia.web.impl.ui.application.views.common.viewnames.UserViews;
  38. import com.hack23.cia.web.impl.ui.application.views.pageclicklistener.PageItemPropertyClickListener;
  39. import com.vaadin.icons.VaadinIcons;
  40. import com.vaadin.server.Responsive;
  41. import com.vaadin.shared.ui.ContentMode;
  42. import com.vaadin.ui.HorizontalLayout;
  43. import com.vaadin.ui.Label;
  44. import com.vaadin.ui.Layout;
  45. import com.vaadin.ui.MenuBar;
  46. import com.vaadin.ui.Panel;
  47. import com.vaadin.ui.VerticalLayout;

  48. /**
  49.  * The Class BallotOverviewPageModContentFactoryImpl.
  50.  */
  51. @Component
  52. public final class BallotOverviewPageModContentFactoryImpl extends AbstractBallotPageModContentFactoryImpl {

  53.     /** The Constant EMBEDDED_ID_PARTY. */
  54.     private static final String EMBEDDED_ID_PARTY = "embeddedId.party";

  55.     /** The Constant COLUMN_ORDER. */
  56.     private static final String[] COLUMN_ORDER = { EMBEDDED_ID_PARTY, "voteDate", "rm", "label", "embeddedId.concern",
  57.             "embeddedId.issue", "approved", "partyApproved", "totalVotes", "partyTotalVotes", "yesVotes",
  58.             "partyYesVotes", "noVotes", "partyNoVotes", "partyAbstainVotes", "abstainVotes", "partyAbsentVotes",
  59.             "absentVotes", "partyAvgBornYear", "avgBornYear", "partyPercentageMale", "percentageMale", "ballotType",
  60.             "embeddedId.ballotId" };

  61.     /** The Constant FIRST_OBJECT. */
  62.     private static final int FIRST_OBJECT = 0;

  63.     /** The Constant HIDE_COLUMNS. */
  64.     private static final String[] HIDE_COLUMNS = { "embeddedId", "partyNoWinner", "partyPercentageYes",
  65.             "partyPercentageNo", "partyPercentageAbsent", "partyPercentageAbstain", "percentageYes", "percentageNo",
  66.             "percentageAbsent", "percentageAbstain", "voteDate", "rm", "label", "embeddedId.concern", "totalVotes",
  67.             "approved", "yesVotes", "noVotes", "ballotType", "abstainVotes", "absentVotes", "embeddedId.ballotId",
  68.             "noWinner" };

  69.     /** The Constant LISTENER. */
  70.     private static final PageItemPropertyClickListener LISTENER = new PageItemPropertyClickListener(
  71.             UserViews.PARTY_VIEW_NAME, EMBEDDED_ID_PARTY);

  72.     /** The Constant NESTED_PROPERTIES. */
  73.     private static final String[] NESTED_PROPERTIES = { "embeddedId.ballotId", "embeddedId.concern", "embeddedId.issue",
  74.             EMBEDDED_ID_PARTY };

  75.     /**
  76.      * Instantiates a new ballot overview page mod content factory impl.
  77.      */
  78.     public BallotOverviewPageModContentFactoryImpl() {
  79.         super();
  80.     }

  81.     /**
  82.      * Creates the content.
  83.      *
  84.      * @param parameters the parameters
  85.      * @param menuBar the menu bar
  86.      * @param panel the panel
  87.      * @return the layout
  88.      */
  89.     @Secured({ "ROLE_ANONYMOUS", "ROLE_USER", "ROLE_ADMIN" })
  90.     @Override
  91.     public Layout createContent(final String parameters, final MenuBar menuBar, final Panel panel) {
  92.         final VerticalLayout panelContent = createPanelContent();
  93.         panel.setContent(panelContent);

  94.         final String pageId = getPageId(parameters);
  95.         final List<ViewRiksdagenVoteDataBallotSummary> ballots = getItem(parameters);

  96.         if (!ballots.isEmpty()) {
  97.             getBallotMenuItemFactory().createBallotMenuBar(menuBar, pageId);

  98.             final DataContainer<ViewRiksdagenVoteDataBallotPartySummary, RiksdagenVoteDataBallotPartyEmbeddedId> dataPartyContainer = getApplicationManager()
  99.                     .getDataContainer(ViewRiksdagenVoteDataBallotPartySummary.class);

  100.             final DataContainer<ViewRiksdagenCommitteeBallotDecisionSummary, ViewRiksdagenCommitteeBallotDecisionEmbeddedId> dataDecisionContainer = getApplicationManager()
  101.                     .getDataContainer(ViewRiksdagenCommitteeBallotDecisionSummary.class);

  102.             final List<ViewRiksdagenVoteDataBallotPartySummary> partyBallotList = dataPartyContainer
  103.                     .findListByEmbeddedProperty(ViewRiksdagenVoteDataBallotPartySummary.class,
  104.                             ViewRiksdagenVoteDataBallotPartySummary_.embeddedId,
  105.                             RiksdagenVoteDataBallotPartyEmbeddedId.class,
  106.                             RiksdagenVoteDataBallotPartyEmbeddedId_.ballotId, pageId);

  107.             final List<ViewRiksdagenCommitteeBallotDecisionSummary> decisionSummaries = dataDecisionContainer
  108.                     .getAllBy(ViewRiksdagenCommitteeBallotDecisionSummary_.ballotId, pageId);

  109.             final boolean useDecisionSummaries = !decisionSummaries.isEmpty();

  110.             String mainTitle;
  111.             String subTitle;
  112.             if (useDecisionSummaries) {
  113.                 mainTitle = BallotViewConstants.OVERVIEW_MAIN_TITLE_PREFIX + decisionSummaries.get(0).getTitle() + " - "
  114.                         + decisionSummaries.get(0).getSubTitle();
  115.             } else {
  116.                 final ViewRiksdagenVoteDataBallotSummary firstBallot = ballots.get(FIRST_OBJECT);
  117.                 mainTitle = BallotViewConstants.OVERVIEW_MAIN_TITLE_PREFIX + firstBallot.getEmbeddedId().getConcern();
  118.             }
  119.             subTitle = BallotViewConstants.OVERVIEW_CARD_BALLOT_INFO;

  120.             CardInfoRowUtil.createPageHeader(panel, panelContent, mainTitle, subTitle,
  121.                     BallotViewConstants.OVERVIEW_PAGE_DESCRIPTION);

  122.             // Card panel
  123.             final Panel cardPanel = new Panel();
  124.             cardPanel.addStyleName("politician-overview-card");
  125.             cardPanel.setWidth("100%");
  126.             cardPanel.setHeightUndefined();
  127.             Responsive.makeResponsive(cardPanel);

  128.             final VerticalLayout cardContent = new VerticalLayout();
  129.             cardContent.setMargin(true);
  130.             cardContent.setSpacing(true);
  131.             cardContent.setWidth("100%");
  132.             cardPanel.setContent(cardContent);

  133.             panelContent.addComponent(cardPanel);
  134.             panelContent.setExpandRatio(cardPanel, ContentRatio.GRID);

  135.             CardInfoRowUtil.createCardHeader(cardContent, BallotViewConstants.OVERVIEW_CARD_BALLOT_INFO);

  136.             // Two-column layout
  137.             final HorizontalLayout attributesLayout = new HorizontalLayout();
  138.             attributesLayout.setSpacing(true);
  139.             attributesLayout.setWidth("100%");
  140.             cardContent.addComponent(attributesLayout);

  141.             // Left column: Ballot Profile (Textual and identifying attributes)
  142.             final VerticalLayout profileDetailsLayout = CardInfoRowUtil.createSectionLayout(BallotViewConstants.OVERVIEW_CARD_BALLOT_PROFILE);

  143.             // Right column: Voting Statistics (Numeric and outcome attributes)
  144.             final VerticalLayout serviceStatsLayout = CardInfoRowUtil.createSectionLayout(BallotViewConstants.OVERVIEW_CARD_VOTING_STATS);

  145.             attributesLayout.addComponents(profileDetailsLayout, serviceStatsLayout);

  146.             // Populate fields depending on data
  147.             if (useDecisionSummaries) {
  148.                 final ViewRiksdagenCommitteeBallotDecisionSummary ds = decisionSummaries.get(FIRST_OBJECT);
  149.                 // Show essential profile fields
  150.                 profileDetailsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_VOTE_DATE, String.valueOf(ds.getVoteDate()), VaadinIcons.CALENDAR, "Date of the vote"));
  151.                 profileDetailsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_TITLE, ds.getTitle(), VaadinIcons.FILE_TEXT_O, "Title of the ballot"));
  152.                 profileDetailsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_SUBTITLE, ds.getSubTitle(), VaadinIcons.FILE_TEXT, "Subtitle of the ballot"));
  153.                 profileDetailsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_DECISION_TYPE, ds.getDecisionType(), VaadinIcons.QUESTION_CIRCLE, "Type of decision"));

  154.                 // Stats fields
  155.                 serviceStatsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_CONCERN, ds.getEmbeddedId().getConcern(), VaadinIcons.CLIPBOARD, "Concern or topic of the ballot"));
  156.                 serviceStatsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_BALLOT_TYPE, ds.getBallotType(), VaadinIcons.BULLETS, "Type of ballot"));
  157.                 serviceStatsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_WINNER, ds.getWinner(), VaadinIcons.TROPHY, "Winner or outcome"));
  158.                 serviceStatsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_APPROVED, String.valueOf(ds.isApproved()), VaadinIcons.CHECK, "Whether the proposal was approved"));

  159.                 // Optional: If still too crowded, remove againstProposal fields
  160.                 // serviceStatsLayout.addComponent(createInfoRow("Against Proposal Parties:", ds.getAgainstProposalParties(), VaadinIcons.WARNING, "Parties against the proposal"));
  161.                 // serviceStatsLayout.addComponent(createInfoRow("Against Proposal Number:", String.valueOf(ds.getAgainstProposalNumber()), VaadinIcons.WARNING, "Number of parties against the proposal"));
  162.             } else {
  163.                 // Non-decision scenario
  164.                 final ViewRiksdagenVoteDataBallotSummary bs = ballots.get(FIRST_OBJECT);
  165.                 // Profile fields
  166.                 profileDetailsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_BALLOT_ID, bs.getEmbeddedId().getBallotId(), VaadinIcons.CLIPBOARD_USER, "Ballot identification"));
  167.                 profileDetailsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_RM, bs.getRm(), VaadinIcons.CALENDAR, "Session (RM) identifier"));
  168.                 profileDetailsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_VOTE_DATE, String.valueOf(bs.getVoteDate()), VaadinIcons.CALENDAR, "Date of the vote"));
  169.                 profileDetailsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_ISSUE, bs.getEmbeddedId().getIssue(), VaadinIcons.CLIPBOARD_TEXT, "The specific issue voted upon"));
  170.                 profileDetailsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_CONCERN, bs.getEmbeddedId().getConcern(), VaadinIcons.CLIPBOARD, "Concern or topic of the ballot"));
  171.                 profileDetailsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_BALLOT_TYPE, bs.getBallotType(), VaadinIcons.BULLETS, "Type of ballot"));
  172.                 profileDetailsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_LABEL, bs.getLabel(), VaadinIcons.FILE_TEXT, "Short label or description"));

  173.                 // Stats fields
  174.                 serviceStatsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_TOTAL_VOTES, String.valueOf(bs.getTotalVotes()), VaadinIcons.GROUP, "Total number of votes cast"));
  175.                 serviceStatsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_YES_VOTES, String.valueOf(bs.getYesVotes()), VaadinIcons.THUMBS_UP, "Number of 'yes' votes"));
  176.                 serviceStatsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_NO_VOTES, String.valueOf(bs.getNoVotes()), VaadinIcons.THUMBS_DOWN, "Number of 'no' votes"));
  177.                 serviceStatsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_ABSTAIN_VOTES, String.valueOf(bs.getAbstainVotes()), VaadinIcons.SPLIT, "Number of abstentions"));
  178.                 serviceStatsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_ABSENT_VOTES, String.valueOf(bs.getAbsentVotes()), VaadinIcons.EXIT_O, "Number of absent voters"));
  179.                 serviceStatsLayout.addComponent(CardInfoRowUtil.createInfoRow(BallotViewConstants.FIELD_APPROVED, String.valueOf(bs.isApproved()), VaadinIcons.CHECK, "Whether the proposal was approved"));
  180.             }

  181.             // Spacer before Party Ballot Summary
  182.             final Label tableDivider = new Label("<hr/>", ContentMode.HTML);
  183.             tableDivider.addStyleName("card-divider");
  184.             tableDivider.setWidth("100%");
  185.             panelContent.addComponent(tableDivider);

  186.             // Party Ballot Summary table
  187.             getGridFactory().createBasicBeanItemNestedPropertiesGrid(panelContent,
  188.                     ViewRiksdagenVoteDataBallotPartySummary.class, partyBallotList,
  189.                     BallotViewConstants.GRID_PARTY_BALLOT_SUMMARY,
  190.                     NESTED_PROPERTIES, COLUMN_ORDER, HIDE_COLUMNS, LISTENER,
  191.                     BallotViewConstants.GRID_EMBEDDED_ID_PARTY, null);

  192.             // Overview layout after table
  193.             final VerticalLayout overviewLayout = new VerticalLayout();
  194.             overviewLayout.setSizeFull();
  195.             panelContent.addComponent(overviewLayout);
  196.             panelContent.setExpandRatio(overviewLayout, ContentRatio.LARGE_FORM);
  197.             getBallotMenuItemFactory().createOverviewPage(overviewLayout, pageId);

  198.             getPageActionEventHelper().createPageEvent(ViewAction.VISIT_BALLOT_VIEW, ApplicationEventGroup.USER, NAME,
  199.                     parameters, pageId);
  200.         }

  201.         return panelContent;
  202.     }


  203.     /**
  204.      * Matches.
  205.      *
  206.      * @param page the page
  207.      * @param parameters the parameters
  208.      * @return true, if successful
  209.      */
  210.     @Override
  211.     public boolean matches(final String page, final String parameters) {
  212.         return PageCommandBallotConstants.COMMAND_BALLOT_OVERVIEW.matches(page, parameters);
  213.     }

  214. }