def __init__(self, name: str, width: RelaxedDimension,
              height: RelaxedDimension, colour: Colour):
     super(Box, self).__init__(ElementStyle(name=name, colour=colour))
     if not isinstance(name, str):
         raise ValueError(f"Invalid name: {name}")
     self.width = Dimension(width)
     self.height = Dimension(height)
Esempio n. 2
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())
Esempio n. 3
0
 def logo_image(self, width: RelaxedDimension) -> Image:
     """filename of the Music Bingo logo"""
     width = Dimension(width)
     #pylint: disable=no-member
     filename, img_width, img_height = self.value.logo
     aspect: float = float(img_width) / float(img_height)
     width = Dimension(width)
     return Image(filename=Assets.get_data_filename(filename),
                  width=width, height=(width / aspect))
 def __init__(self, filename: Path, width: RelaxedDimension,
              height: RelaxedDimension):
     super(Image, self).__init__(None)
     if not isinstance(filename, Path):
         cls = type(filename)
         raise ValueError(f"Invalid filename class : {cls}")
     self.filename = filename
     self.width = Dimension(width)
     self.height = Dimension(height)
Esempio n. 5
0
 def __init__(self,
              top: RelaxedDimension = 0,
              right: RelaxedDimension = 0,
              bottom: RelaxedDimension = 0,
              left: RelaxedDimension = 0):
     self.top = Dimension(top)
     self.right = Dimension(right)
     self.bottom = Dimension(bottom)
     self.left = Dimension(left)
Esempio n. 6
0
 def test_render_image(self):
     """test rendering DG.Image to a reportlab image"""
     filename, width, height = ('logo_banner.jpg', 7370 / 50.0, 558 / 50.0)
     ext_filename = self.extra_files / filename
     dg_img = DG.Image(ext_filename, width=width, height=height)
     pdfgen = PDFGenerator()
     pdf_img = pdfgen.render_image(dg_img)
     self.assertEqual(pdf_img.filename, str(dg_img.filename))
     self.assertAlmostEqual(pdf_img.drawWidth, Dimension(width).points())
     self.assertAlmostEqual(pdf_img.drawHeight, Dimension(height).points())
Esempio n. 7
0
 def test_render_horiz_line(self):
     """test rendering DG.HorizontalLine to a reportlab line"""
     dg_line = DG.HorizontalLine(name='hr',
                                 width="5in",
                                 colour='blue',
                                 thickness=2)
     pdfgen = PDFGenerator()
     pdf_line = pdfgen.render_horiz_line(dg_line)
     self.assertAlmostEqual(pdf_line.width, Dimension("5in").points())
     self.assertAlmostEqual(pdf_line.lineWidth, Dimension(2).points())
 def __init__(self,
              pagesize: PageSizes,
              topMargin: RelaxedDimension = INCH,
              bottomMargin: RelaxedDimension = INCH,
              leftMargin: RelaxedDimension = INCH,
              rightMargin: RelaxedDimension = INCH,
              title: Optional[str] = None):
     self.pagesize = pagesize
     self.top_margin = Dimension(topMargin)
     self.bottom_margin = Dimension(bottomMargin)
     self.left_margin = Dimension(leftMargin)
     self.right_margin = Dimension(rightMargin)
     self.title = title
     self._elements: List[Element] = []
Esempio n. 9
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)
Esempio n. 10
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())
Esempio n. 11
0
 def test_render_empty_document(self):
     """test rendering DG.Document to a reportlab document"""
     tmpfile = os.path.join(self.tmpdir, "test.pdf")
     dg_doc = DG.Document(pagesize=PageSizes.A4,
                          topMargin=0.0,
                          bottomMargin=0.0,
                          leftMargin=10,
                          rightMargin=20,
                          title="Empty document")
     pdfgen = PDFGenerator()
     pdf_doc = pdfgen.render_document(tmpfile, dg_doc)
     self.assertEqual(pdf_doc.topMargin, 0)
     self.assertEqual(pdf_doc.bottomMargin, 0)
     self.assertAlmostEqual(pdf_doc.leftMargin, Dimension(10).points())
     self.assertAlmostEqual(pdf_doc.rightMargin, Dimension(20).points())
     self.assertAlmostEqual(pdf_doc.pagesize[0],
                            PageSizes.A4.width().points())
     self.assertAlmostEqual(pdf_doc.pagesize[1],
                            PageSizes.A4.height().points())
     self.assertEqual(pdf_doc.title, dg_doc.title)
Esempio n. 12
0
 def __init__(self,
              name: str,
              width: RelaxedDimension,
              thickness: RelaxedDimension,
              colour: Colour,
              dash: Optional[List[RelaxedDimension]] = None):
     """
     width - length of line
     thickness - thickness of line
     colour - colour of line
     dash - array of lengths used to specify length of each dash and the
            gap between each dash
     """
     super(HorizontalLine,
           self).__init__(ElementStyle(name=name, colour=colour))
     if not isinstance(name, str):
         raise ValueError(f"Invalid name: {name}")
     self.width = Dimension(width)
     self.thickness = Dimension(thickness)
     self.dash: Optional[List[Dimension]] = None
     if dash is not None:
         self.dash = [Dimension(w) for w in dash]
Esempio n. 13
0
 def __init__(self,
              name: str,
              text: str,
              size: RelaxedDimension,
              style: ElementStyle,
              borderColour: Optional[Union[Colour, str]] = None,
              borderWidth: float = 1.0):
     super(Checkbox, self).__init__(style)
     self.name = name
     self.text = text
     self.size = Dimension(size)
     self.border_colour = borderColour
     self.border_width = borderWidth
Esempio n. 14
0
 def test_render_box(self, mock_table):
     """test rendering DG.Box to a reportlab table"""
     dg_box = DG.Box('test-box', width="10in", height=0, colour='black')
     pdfgen = PDFGenerator()
     pdfgen.render_box(dg_box)
     _, args, kwargs = mock_table.mock_calls[0]
     col_width = Dimension("10.0in").points()
     expected_styles = [("LINEBELOW", (0, 0), (-1, -1), 1, lib.colors.black)
                        ]
     self.assertEqual(len(args), 1)  # one positonal argument (data)
     self.assertEqual(len(args[0]), 1)  # data has one row
     self.assertEqual(len(args[0][0]), 1)  # row has one cell
     self.assertEqual(args[0][0][0], "")
     self.assertStyleListsEqual(expected_styles, kwargs['style'])
     self.assertEqual(len(kwargs['colWidths']), 1)
     self.assertAlmostEqual(col_width, kwargs['colWidths'][0])
     self.assertEqual(len(kwargs['rowHeights']), 1)
     self.assertAlmostEqual(0.0, kwargs['rowHeights'][0])
Esempio n. 15
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())
Esempio n. 16
0
 def __init__(self, width: RelaxedDimension, height: RelaxedDimension):
     super(Spacer, self).__init__(None)
     self.width = Dimension(width)
     self.height = Dimension(height)
Esempio n. 17
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)