예제 #1
0
    def generate_card_results(self, tracks: List[Song],
                              cards: List[BingoTicket]):
        """generate PDF showing when each ticket wins"""
        doc = DG.Document(pagesize=PageSizes.A4,
                          title=f'{self.options.game_id} - {self.options.title}',
                          topMargin="0.25in",
                          bottomMargin="0.25in",
                          rightMargin="0.25in",
                          leftMargin="0.25in")

        doc.append(self.options.palette.logo_image("6.2in"))
        doc.append(DG.Spacer(width=0, height="0.05in"))

        doc.append(DG.Paragraph(
            f'Results For Game Number: <b>{self.options.game_id}</b>',
            self.TEXT_STYLES['results-heading']))
        doc.append(DG.Paragraph(
            self.options.title,
            self.TEXT_STYLES['results-title']))

        pstyle = self.TEXT_STYLES['results-cell']
        heading: DG.TableRow = [
            DG.Paragraph('<b>Ticket Number</b>', pstyle),
            DG.Paragraph('<b>Wins after track</b>', pstyle),
            DG.Paragraph('<b>Start Time</b>', pstyle),
        ]
        data: List[DG.TableRow] = []

        cards = copy.copy(cards)
        cards.sort(key=lambda card: card.ticket_number, reverse=False)
        for card in cards:
            win_point = self.get_when_ticket_wins(tracks, card)
            song = tracks[win_point - 1]
            data.append([
                DG.Paragraph(f'{card.ticket_number}', pstyle),
                DG.Paragraph(
                    f'Track {win_point} - {song.title} ({song.artist})',
                    pstyle),
                DG.Paragraph(Duration(song.start_time).format(), pstyle)
            ])

        col_widths: List[Dimension] = [
            Dimension("0.75in"), Dimension("5.5in"), Dimension("0.85in"),
        ]
        hstyle = pstyle.replace(
            name='results-table-heading',
            background=self.options.palette.title_bg)
        tstyle = TableStyle(name='results-table',
                            borderColour=Colour('black'),
                            borderWidth=1.0,
                            gridColour=Colour('black'),
                            gridWidth=0.5,
                            verticalAlignment=VerticalAlignment.CENTER,
                            headingStyle=hstyle)
        table = DG.Table(data, heading=heading, repeat_heading=True,
                         colWidths=col_widths, style=tstyle)
        doc.append(table)
        filename = str(self.options.ticket_results_output_name())
        self.doc_gen.render(filename, doc, Progress())
예제 #2
0
    def generate_tickets_pdf(self, cards: List[BingoTicket]) -> None:
        """generate a PDF file containing all the Bingo tickets"""
        doc = DG.Document(pagesize=PageSizes.A4,
                          title=f'{self.options.game_id} - {self.options.title}',
                          topMargin="0.15in",
                          rightMargin="0.15in",
                          bottomMargin="0.15in",
                          leftMargin="0.15in")
        page: int = 1
        num_cards: int = len(cards)
        cards_per_page: int = 3
        if self.options.rows == 2:
            cards_per_page = 4
        elif self.options.rows > 3:
            cards_per_page = 2
        id_style = self.TEXT_STYLES['ticket-id']
        title_style = id_style.replace('ticket-title',
                                       alignment=HorizontalAlignment.LEFT)

        for count, card in enumerate(cards, start=1):
            self.progress.text = f'Card {count}/{num_cards}'
            self.progress.pct = 100.0 * float(count) / float(num_cards)
            self.render_bingo_ticket(card, doc)
            data: List[DG.TableRow] = [[
                DG.Paragraph(self.options.title, title_style),
                DG.Paragraph(
                    f"{self.options.game_id} / T{card.ticket_number} / P{page}",
                    id_style),
            ]]
            tstyle = TableStyle(name='ticket-id',
                                borderWidth=0,
                                gridWidth=0,
                                verticalAlignment=VerticalAlignment.CENTER)
            table = DG.Table(
                data,
                colWidths=[Dimension(80), Dimension(80)],
                rowHeights=[Dimension(f'16pt')],
                style=tstyle)
            doc.append(table)
            if count % cards_per_page != 0:
                doc.append(
                    DG.HorizontalLine('hline', width="100%", thickness="1px",
                                      colour=Colour('gray'), dash=[2, 2]))
                doc.append(DG.Spacer(width=0, height="0.08in"))
            else:
                doc.append(DG.PageBreak())
                page += 1
        filename = str(self.options.bingo_tickets_output_name())
        self.doc_gen.render(filename, doc, Progress())
예제 #3
0
    def render_bingo_ticket(self, card: BingoTicket, doc: DG.Document) -> None:
        """
        Render a Bingo ticket into the specified Document.
        Each ticket has the Music Bingo logo followed by a
        table.
        """
        doc.append(self.options.palette.logo_image("6.2in"))

        pstyle = self.TEXT_STYLES['ticket-cell']
        data: List[DG.TableRow] = []
        ranges: List[Tuple[int, int]] = []
        for row_index in range(self.options.rows):
            ranges.append((row_index * self.options.columns,
                           (1 + row_index) * self.options.columns))
        for start, end in ranges:
            row: DG.TableRow = []
            for index in range(start, end):
                items: List[DG.Paragraph] = [
                    DG.Paragraph(card.card_tracks[index].title, pstyle),
                ]
                if self.should_include_artist(card.card_tracks[index]):
                    items.append(
                        DG.Paragraph(f'<b>{card.card_tracks[index].artist}</b>',
                                     pstyle))
                row.append(items)
            data.append(row)

        column_width = Dimension("1.54in")
        if self.options.columns > 5:
            column_width *= 5.0 / float(self.options.columns)
        row_height = Dimension("0.97in")

        tstyle = TableStyle(name='bingo-card',
                            borderColour=Colour('black'),
                            borderWidth=2.0,
                            gridColour=Colour('black'),
                            gridWidth=0.5,
                            verticalAlignment=VerticalAlignment.CENTER)
        col_widths: List[Dimension] = [column_width] * self.options.columns
        row_heights: List[Dimension] = [row_height] * self.options.rows
        table = DG.Table(data, colWidths=col_widths, rowHeights=row_heights,
                         style=tstyle)
        for box_row in range(0, self.options.rows):
            for box_col in range(0, self.options.columns):
                table.style_cells(
                    DG.CellPos(col=box_col, row=box_row),
                    DG.CellPos(col=box_col, row=box_row),
                    background=card.box_colour_style(box_col, box_row))
        doc.append(table)
예제 #4
0
    def generate_track_listing(self, tracks: List[Song]) -> None:
        """generate a PDF version of the track order in the game"""
        assert len(tracks) > 0
        doc = DG.Document(
            PageSizes.A4,
            topMargin="0.25in",
            bottomMargin="0.25in",
            leftMargin="0.35in",
            rightMargin="0.35in",
            title=f'{self.options.game_id} - {self.options.title}')

        doc.append(self.options.palette.logo_image("6.2in"))
        doc.append(DG.Spacer(width=0, height="0.05in"))

        doc.append(
            DG.Paragraph(
                f'Track Listing For Game Number: <b>{self.options.game_id}</b>',
                self.TEXT_STYLES['track-heading']))

        doc.append(
            DG.Paragraph(self.options.title, self.TEXT_STYLES['track-title']))

        cell_style = self.TEXT_STYLES['track-cell']
        heading: DG.TableRow = [
            DG.Paragraph('<b>Order</b>', cell_style),
            DG.Paragraph('<b>Title</b>', cell_style),
            DG.Paragraph('<b>Artist</b>', cell_style),
            DG.Paragraph('<b>Start Time</b>', cell_style),
            DG.Paragraph('', cell_style),
        ]

        data: List[DG.TableRow] = []

        for index, song in enumerate(tracks, start=1):
            order = DG.Paragraph(f'<b>{index}</b>', cell_style)
            title = DG.Paragraph(song.title, cell_style)
            if self.should_include_artist(song):
                artist = DG.Paragraph(song.artist, cell_style)
            else:
                artist = DG.Paragraph('', cell_style)
            start = DG.Paragraph(
                Duration(song.start_time).format(), cell_style)
            end_box = DG.Paragraph('', cell_style)
            data.append([order, title, artist, start, end_box])

        col_widths = [
            Dimension("0.55in"),
            Dimension("2.9in"),
            Dimension("2.9in"),
            Dimension("0.85in"),
            Dimension("0.2in")
        ]

        hstyle = cell_style.replace(name='track-table-heading',
                                    background=self.options.palette.title_bg)
        tstyle = TableStyle(name='track-table',
                            borderColour=Colour('black'),
                            borderWidth=1.0,
                            gridColour=Colour('black'),
                            gridWidth=0.5,
                            verticalAlignment=VerticalAlignment.CENTER,
                            headingStyle=hstyle)
        table = DG.Table(data,
                         heading=heading,
                         repeat_heading=True,
                         colWidths=col_widths,
                         style=tstyle)
        doc.append(table)
        filename = str(self.options.track_listing_output_name())
        self.doc_gen.render(filename, doc, Progress())
예제 #5
0
    def test_render_bingo_ticket_table(self, mock_table):
        """
        Test converting a documentgenerator Table to a reportlab table.
        This test uses example data from the Bingo ticket generator
        """
        cstyle = DG.ElementStyle('ticket-cell',
                                 colour='black',
                                 alignment=HorizontalAlignment.CENTER,
                                 fontSize=12,
                                 leading=12,
                                 padding=Padding(bottom=4))

        data: List[DG.TableRow] = []
        for start, end in ((0, 5), (5, 10), (10, 15)):
            row: DG.TableRow = []
            for index in range(start, end):
                items: List[DG.TableCell] = [
                    DG.Paragraph(f'Title {index}', cstyle),
                    DG.Paragraph(f'<b>Artist {index}</b>', cstyle),
                ]
                row.append(items)
            data.append(row)

        column_width = Dimension("1.54in")
        row_height = Dimension("1.0in")
        col_widths = (column_width, column_width, column_width, column_width,
                      column_width)
        row_heights = (row_height, row_height, row_height)

        tstyle = DG.TableStyle(name='bingo-ticket',
                               borderColour=Colour('black'),
                               borderWidth=1.0,
                               colour='black',
                               gridColour=Colour('black'),
                               gridWidth=0.5,
                               padding=Padding(0, 0, 0, 0),
                               alignment=HorizontalAlignment.CENTER,
                               verticalAlignment=VerticalAlignment.CENTER)

        dg_table = DG.Table(data,
                            colWidths=col_widths,
                            rowHeights=row_heights,
                            style=tstyle)
        box_colours: List[Colour] = []
        for name, value in CSS_COLOUR_NAMES.items():
            if name == 'black':
                continue
            box_colours.append(Colour(value))
        expected_styles = [
            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
            ('BOX', (0, 0), (-1, -1), 1.0, lib.colors.black),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 0),
            ('FONTSIZE', (0, 0), (-1, -1), tstyle.font_size),
            ('GRID', (0, 0), (-1, -1), 0.5, lib.colors.black),
            ('LEADING', (0, 0), (-1, -1), tstyle.leading),
            ('LEFTPADDING', (0, 0), (-1, -1), 0),
            ('RIGHTPADDING', (0, 0), (-1, -1), 0),
            ('TEXTCOLOR', (0, 0), (-1, -1), lib.colors.black),
            ('TOPPADDING', (0, 0), (-1, -1), 0),
            ('VALIGN', (0, 0), (-1, -1), 'CENTER'),
        ]
        index = 0
        for box_row in range(0, 3):
            for box_col in range(0, 5):
                box_style = DG.ElementStyle(
                    name=f'bingo-cell-r{box_row}-c{box_col}',
                    alignment=HorizontalAlignment.CENTER,
                    background=box_colours[index % len(box_colours)])
                dg_table.style_cells(DG.CellPos(col=box_col, row=box_row),
                                     DG.CellPos(col=box_col, row=box_row),
                                     box_style)
                expected_styles.append((
                    'BACKGROUND',
                    (box_col, box_row),
                    (box_col, box_row),
                    lib.colors.HexColor(box_style.background.css()),
                ))
                index += 1

        pdfgen = PDFGenerator()
        pdf_styles = pdfgen.translate_table_style(dg_table,
                                                  first_row=0,
                                                  last_row=len(data),
                                                  num_cols=5)
        self.assertStyleListsEqual(expected_styles, pdf_styles)
        pdfgen.render_table(dg_table)
        _, args, kwargs = mock_table.mock_calls[0]
        self.assertListsEqual(data, args[0])
        self.assertStyleListsEqual(expected_styles, kwargs['style'])
        for dg_col, pdf_col in zip(col_widths, kwargs['colWidths']):
            self.assertAlmostEqual(dg_col.points(), pdf_col)
        for dg_row, pdf_row in zip(row_heights, kwargs['rowHeights']):
            self.assertAlmostEqual(dg_row.points(), pdf_row)
예제 #6
0
    def test_render_results_table(self, mock_table):
        """
        Test converting a documentgenerator Table to a reportlab table.
        This test uses example data from the ticket results table
        """
        cstyle = DG.ElementStyle(name='results-cell',
                                 colour=Colour('black'),
                                 alignment=HorizontalAlignment.CENTER,
                                 fontSize=10,
                                 leading=10)
        heading: DG.TableRow = [
            DG.Paragraph('<b>Ticket Number</b>', cstyle),
            DG.Paragraph('<b>Wins after track</b>', cstyle),
            DG.Paragraph('<b>Start Time</b>', cstyle),
        ]
        data: List[DG.TableRow] = [
            [
                DG.Paragraph('1', cstyle),
                DG.Paragraph('2', cstyle),
                DG.Paragraph('3:45', cstyle),
            ],
            [
                DG.Paragraph('2', cstyle),
                DG.Paragraph('3', cstyle),
                DG.Paragraph('4:45', cstyle),
            ],
            [
                DG.Paragraph('3', cstyle),
                DG.Paragraph('1', cstyle),
                DG.Paragraph('1:45', cstyle),
            ],
        ]
        hstyle = DG.ElementStyle(name='heading',
                                 fontSize=12,
                                 background=Colour('blue'))
        col_widths: List[Dimension] = list(map(Dimension, [20, 125, 20]))
        tstyle = DG.TableStyle(name='test-table',
                               borderColour=Colour('black'),
                               borderWidth=1.0,
                               gridColour=Colour('black'),
                               gridWidth=0.5,
                               alignment=HorizontalAlignment.LEFT,
                               verticalAlignment=VerticalAlignment.CENTER,
                               headingStyle=hstyle)

        dg_table = DG.Table(data,
                            heading=heading,
                            repeat_heading=True,
                            colWidths=col_widths,
                            style=tstyle)
        pdfgen = PDFGenerator()
        expected_styles = [
            # table styles:
            ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
            ('BOX', (0, 0), (-1, -1), 1, lib.colors.black),
            ('FONTSIZE', (0, 0), (-1, -1), tstyle.font_size),
            ('GRID', (0, 0), (-1, -1), 0.5, lib.colors.black),
            ('LEADING', (0, 0), (-1, -1), tstyle.leading),
            ('VALIGN', (0, 0), (-1, -1), 'CENTER'),
            # heading row styles:
            ('BACKGROUND', (0, 0), (2, 0), lib.colors.blue),
            ('FONTSIZE', (0, 0), (2, 0), hstyle.font_size),
        ]
        pdf_styles = pdfgen.translate_table_style(dg_table,
                                                  first_row=1,
                                                  last_row=(len(data) + 1),
                                                  num_cols=3)
        self.assertStyleListsEqual(expected_styles, pdf_styles)
        pdfgen.render_table(dg_table)
        _, args, kwargs = mock_table.mock_calls[0]

        self.assertListsEqual([heading] + data, args[0])
        self.assertStyleListsEqual(expected_styles, kwargs['style'])
        for dg_col, pdf_col in zip(col_widths, kwargs['colWidths']):
            self.assertAlmostEqual(dg_col.points(), pdf_col)