from decimal import Decimal
import os
import sys
import platform  
import tempfile
from PySide2.QtWidgets import QWidget, QToolTip, QPushButton, QApplication
from PySide2.QtGui import QPainter, QFont, QDesktopServices, QPen, QColor, QTextOption, QPageLayout, QPageSize
from PySide2.QtPrintSupport import QPrinter, QPrintDialog
from PySide2.QtCore import Qt, QUrl, QRectF, QMarginsF, QSizeF
    
class Example(QWidget):
    
    def __init__(self):
        super().__init__()        
        self.initUI()
        self.printer = QPrinter(QPrinter.HighResolution) # QPrinter.HighResolution
        self.printer.setPageSize(QPrinter.A4)
        self.printer.setOutputFormat(QPrinter.PdfFormat)
        print("Printercheck1:",  self.printer.isValid())
        self.tempdir = tempfile.mkdtemp(prefix="PyTesting-")
        self._Windows = False
        if platform.system() == "Windows":
                self._Windows = True
        
        
    def initUI(self):
        
        QToolTip.setFont(QFont('SansSerif', 10))
        
        self.setToolTip('Try printing')
        
        btn = QPushButton('Print portrait-pdf', self)
        btn.setToolTip('This should produce a PDF in portrait mode in A4 format')
        btn.resize(btn.sizeHint())
        btn.move(60, 50)
        btn.clicked.connect(lambda:self.exPrint(pdf=True,  lscp=False))
        
        btn2 = QPushButton('Print landscape-pdf', self)
        btn2.setToolTip('This should produce a PDF in landscape mode in A4 format')
        btn2.resize(btn.sizeHint())
        btn2.move(60, 100)
        btn2.clicked.connect(lambda:self.exPrint(pdf=True,  lscp=True))
        
        btn3 = QPushButton('Print dialog portrait', self)
        btn3.setToolTip('Open Print-Dialog portrait')
        btn3.resize(btn.sizeHint())
        btn3.move(60, 150)
        btn3.clicked.connect(lambda:self.exPrint(pdf=False,  lscp=False))
        
        btn4 = QPushButton('Print dialog lscp', self)
        btn4.setToolTip('Open Print-Dialog landscape')
        btn4.resize(btn.sizeHint())
        btn4.move(60, 200)
        btn4.clicked.connect(lambda:self.exPrint(pdf=False,  lscp=True))
        
        self.setGeometry(400, 400, 400, 300)
        self.setWindowTitle('Printing-Test')    
        self.show()

    def printsettings(self, pdf=True, name="", landscp=False):
        printservice = None
        painter = None
        filename = None
        if pdf or self._Windows:
            printservice = self.printer
            if landscp:
                try:
                    printservice.setPageOrientation(QPageLayout.Landscape)
                    print("Printercheck2:",  printservice.isValid())
                except Exception as e:
                    print("Exception in printersettings:", e.args[0])
            else:
                try:
                    printservice.setPageOrientation(QPageLayout.Portrait)
                except Exception as e:
                    print("Exception in printersettings::", e.args[0])
            print("Current settings:", printservice.pageLayout().pageSize().size(QPageSize.Millimeter), printservice.pageLayout().orientation())
            if self._Windows:
                slash = "\\"
            else:
                slash = "/"
            filename = self.tempdir + slash + name + ".pdf"
            self.printer.setOutputFileName(filename)
            self.printer.setDocName(filename)
        else:
            filename = ""
            printservice = QPrinter(300)  # 300 QPrinter.HighResolution
            printservice.setFullPage(True)
            printservice.setPageSize(QPrinter.A4)
            if landscp:
                try:
                    printservice.setPageOrientation(QPageLayout.Landscape)
                except Exception as e:
                    print("Exception in printersettings:", e.args[0])
            else:
                try:
                    printservice.setPageOrientation(QPageLayout.Portrait)
                except Exception as e:
                    print("Exception in printersettings:", e.args[0])
            dialog = QPrintDialog(printservice, None)
            if not dialog.exec_():
                return (None, None, None)
        if printservice is not None:
            painter = QPainter(printservice)
            painter.setRenderHints(QPainter.TextAntialiasing)
            painter.resetTransform()
            scale = Decimal(1)
            painter.scale(scale, scale)
        return (printservice, painter, filename)
    
    def finishjob(self, painter, filename, pdf=True):
        painter.end()
        if pdf:
            url = QUrl.fromLocalFile(filename)
            QDesktopServices.openUrl(url)
        else:
            if self._Windows:
                try:
                    os.startfile(filename, "print")
                except Exception as e:
                    print("Exception in attempt to print file:", filename, "ErrorMessage:", e.args[0])
    
        
    def mm2pt(self, x):
        """used to calculate millimeters to point, for passing lengths in millimeter to the painter"""
        if type(x) == float or type(x) == int:
            return int(round(Decimal("360")/Decimal("127")*Decimal(x)))
        else:
            return None

    def fromLeft(self, x):
        """distance from left paper edge in millimeters"""
        return (self.mm2pt(x) - 18)

    def fromTop(self, y):
        """distance from top edge of paper in millimeters"""
        return (self.mm2pt(y) - 8)
        
    def exPrint(self, pdf=True,  lscp=False):
        name = 'printingexample'
        printmode = self.printsettings(pdf, name,  lscp)
        printservice = printmode[0]
        painter = printmode[1]
        filename = printmode[2]
        if printservice is not None:
            pen = QPen(QColor(0, 0, 0))
            pen.setWidthF(0.4)
            painter.setPen(pen)
            sansFont = QFont("Sans Serif", 9, weight=45)
            painter.setFont(sansFont)
            x1 = self.fromLeft(17)
            x2 = x1 + self.mm2pt(200)
            t_left = QTextOption()
            t_left.setAlignment(Qt.AlignLeft)
            t_right = QTextOption()
            t_right.setAlignment(Qt.AlignRight)
            height = 12
            rect = QRectF(x1, self.mm2pt(10), x2 - x1, 2*height)
            painter.drawText(rect, "top left", t_left)
            painter.drawText(rect, "top right", t_right)
            try:
                self.finishjob(painter, filename, pdf)
            except (PermissionError, ProcessLookupError, FileExistsError, FileNotFoundError,
                    AttributeError, AssertionError, NotADirectoryError) as e:
                print("Failed to open or print document. ErrorMessage:",  e.args[0])
        else:
            print("Printservice not available.")

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
