OCA reporting engine fork for dev and update.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

315 lines
13 KiB

  1. # Copyright 2018 Akretion (http://www.akretion.com)
  2. # @author: Alexis de Lattre <alexis.delattre@akretion.com>
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. from odoo import api, fields, models, _
  5. from odoo.exceptions import ValidationError
  6. import logging
  7. logger = logging.getLogger(__name__)
  8. class Py3oPdfOptions(models.Model):
  9. _name = 'py3o.pdf.options'
  10. _description = 'Define PDF export options for Libreoffice'
  11. name = fields.Char(required=True)
  12. # GENERAL TAB
  13. # UseLosslessCompression (bool)
  14. image_compression = fields.Selection([
  15. ('lossless', 'Lossless Compression'),
  16. ('jpeg', 'JPEG Compression'),
  17. ], string='Image Compression', default='jpeg')
  18. # Quality (int)
  19. image_jpeg_quality = fields.Integer(
  20. string='Image JPEG Quality', default=90,
  21. help="Enter a percentage between 0 and 100.")
  22. # ReduceImageResolution (bool) and MaxImageResolution (int)
  23. image_reduce_resolution = fields.Selection([
  24. ('none', 'Disable'),
  25. ('75', '75 DPI'),
  26. ('150', '150 DPI'),
  27. ('300', '300 DPI'),
  28. ('600', '600 DPI'),
  29. ('1200', '1200 DPI'),
  30. ], string='Reduce Image Resolution', default='300')
  31. watermark = fields.Boolean('Sign With Watermark')
  32. # Watermark (string)
  33. watermark_text = fields.Char('WaterMark Text')
  34. # UseTaggedPDF (bool)
  35. tagged_pdf = fields.Boolean('Tagged PDF (add document structure)')
  36. # SelectPdfVersion (int)
  37. # 0 = PDF 1.4 (default selection).
  38. # 1 = PDF/A-1 (ISO 19005-1:2005)
  39. pdfa = fields.Boolean(
  40. 'Archive PDF/A-1a (ISO 19005-1)',
  41. help="If you enable this option, you will not be able to "
  42. "password-protect the document or apply other security settings.")
  43. # ExportFormFields (bool)
  44. pdf_form = fields.Boolean('Create PDF Form', default=True)
  45. # FormsType (int)
  46. pdf_form_format = fields.Selection([
  47. ('0', 'FDF'),
  48. ('1', 'PDF'),
  49. ('2', 'HTML'),
  50. ('3', 'XML'),
  51. ], string='Submit Format', default='0')
  52. # AllowDuplicateFieldNames (bool)
  53. pdf_form_allow_duplicate = fields.Boolean('Allow Duplicate Field Names')
  54. # ExportBookmarks (bool)
  55. export_bookmarks = fields.Boolean('Export Bookmarks', default=True)
  56. # ExportPlaceholders (bool)
  57. export_placeholders = fields.Boolean('Export Placeholders', default=True)
  58. # ExportNotes (bool)
  59. export_comments = fields.Boolean('Export Comments')
  60. # ExportHiddenSlides (bool) ??
  61. export_hidden_slides = fields.Boolean(
  62. 'Export Automatically Insered Blank Pages')
  63. # Doesn't make sense to have the option "View PDF after export" ! :)
  64. # INITIAL VIEW TAB
  65. # InitialView (int)
  66. initial_view = fields.Selection([
  67. ('0', 'Page Only'),
  68. ('1', 'Bookmarks and Page'),
  69. ('2', 'Thumbnails and Page'),
  70. ], string='Panes', default='0')
  71. # InitialPage (int)
  72. initial_page = fields.Integer(string='Initial Page', default=1)
  73. # Magnification (int)
  74. magnification = fields.Selection([
  75. ('0', 'Default'),
  76. ('1', 'Fit in Window'),
  77. ('2', 'Fit Width'),
  78. ('3', 'Fit Visible'),
  79. ('4', 'Zoom'),
  80. ], string='Magnification', default='0')
  81. # Zoom (int)
  82. zoom = fields.Integer(
  83. string='Zoom Factor', default=100,
  84. help='Possible values: from 50 to 1600')
  85. # PageLayout (int)
  86. page_layout = fields.Selection([
  87. ('0', 'Default'),
  88. ('1', 'Single Page'),
  89. ('2', 'Continuous'),
  90. ('3', 'Continuous Facing'),
  91. ], string='Page Layout', default='0')
  92. # USER INTERFACE TAB
  93. # ResizeWindowToInitialPage (bool)
  94. resize_windows_initial_page = fields.Boolean(
  95. string='Resize Windows to Initial Page')
  96. # CenterWindow (bool)
  97. center_window = fields.Boolean(string='Center Window on Screen')
  98. # OpenInFullScreenMode (bool)
  99. open_fullscreen = fields.Boolean(string='Open in Full Screen Mode')
  100. # DisplayPDFDocumentTitle (bool)
  101. display_document_title = fields.Boolean(string='Display Document Title')
  102. # HideViewerMenubar (bool)
  103. hide_menubar = fields.Boolean(string='Hide Menubar')
  104. # HideViewerToolbar (bool)
  105. hide_toolbar = fields.Boolean(string='Hide Toolbar')
  106. # HideViewerWindowControls (bool)
  107. hide_window_controls = fields.Boolean(string='Hide Windows Controls')
  108. # OpenBookmarkLevels (int) -1 = all (default) from 1 to 10
  109. open_bookmark_levels = fields.Selection([
  110. ('-1', 'All Levels'),
  111. ('1', '1'),
  112. ('2', '2'),
  113. ('3', '3'),
  114. ('4', '4'),
  115. ('5', '5'),
  116. ('6', '6'),
  117. ('7', '7'),
  118. ('8', '8'),
  119. ('9', '9'),
  120. ('10', '10'),
  121. ], default='-1', string='Visible Bookmark Levels')
  122. # LINKS TAB
  123. # ExportBookmarksToPDFDestination (bool)
  124. export_bookmarks_named_dest = fields.Boolean(
  125. string='Export Bookmarks as Named Destinations')
  126. # ConvertOOoTargetToPDFTarget (bool)
  127. convert_doc_ref_to_pdf_target = fields.Boolean(
  128. string='Convert Document References to PDF Targets')
  129. # ExportLinksRelativeFsys (bool)
  130. export_filesystem_urls = fields.Boolean(
  131. string='Export URLs Relative to Filesystem')
  132. # PDFViewSelection -> mnDefaultLinkAction (int)
  133. cross_doc_link_action = fields.Selection([
  134. ('0', 'Default'),
  135. ('1', 'Open with PDF Reader Application'),
  136. ('2', 'Open with Internet Browser'),
  137. ], string='Cross-document Links', default='0')
  138. # SECURITY TAB
  139. # EncryptFile (bool)
  140. encrypt = fields.Boolean('Encrypt')
  141. # DocumentOpenPassword (char)
  142. document_password = fields.Char(string='Document Password')
  143. # RestrictPermissions (bool)
  144. restrict_permissions = fields.Boolean('Restrict Permissions')
  145. # PermissionPassword (char)
  146. permission_password = fields.Char(string='Permission Password')
  147. # TODO PreparedPasswords + PreparedPermissionPassword
  148. # I don't see those fields in the LO interface !
  149. # But they are used in the LO code...
  150. # Printing (int)
  151. printing = fields.Selection([
  152. ('0', 'Not Permitted'),
  153. ('1', 'Low Resolution (150 dpi)'),
  154. ('2', 'High Resolution'),
  155. ], string='Printing', default='2')
  156. # Changes (int)
  157. changes = fields.Selection([
  158. ('0', 'Not Permitted'),
  159. ('1', 'Inserting, Deleting and Rotating Pages'),
  160. ('2', 'Filling in Form Fields'),
  161. ('3', 'Commenting, Filling in Form Fields'),
  162. ('4', 'Any Except Extracting Pages'),
  163. ], string='Changes', default='4')
  164. # EnableCopyingOfContent (bool)
  165. content_copying_allowed = fields.Boolean(
  166. string='Enable Copying of Content', default=True)
  167. # EnableTextAccessForAccessibilityTools (bool)
  168. text_access_accessibility_tools_allowed = fields.Boolean(
  169. string='Enable Text Access for Accessibility Tools', default=True)
  170. # DIGITAL SIGNATURE TAB
  171. # This will be possible but not easy
  172. # Because the certificate parameter is a pointer to a certificate
  173. # already registered in LO
  174. # On Linux LO reuses the Mozilla certificate store (on Windows the
  175. # one from Windows)
  176. # But there seems to be some possibilities to send this certificate via API
  177. # It seems you can add temporary certificates during runtime:
  178. # https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1security_1_1XCertificateContainer.html
  179. # Here is an API to retrieve the known certificates:
  180. # https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1xml_1_1crypto_1_1XSecurityEnvironment.html
  181. # Thanks to 'samuel_m' on libreoffice-dev IRC chan for pointing me to this
  182. @api.constrains(
  183. 'image_jpeg_quality', 'initial_page', 'pdfa',
  184. 'cross_doc_link_action', 'magnification', 'zoom')
  185. def check_pdf_options(self):
  186. for opt in self:
  187. if opt.image_jpeg_quality > 100 or opt.image_jpeg_quality < 1:
  188. raise ValidationError(_(
  189. "The parameter Image JPEG Quality must be between 1 %%"
  190. " and 100 %% (current value: %s %%)")
  191. % opt.image_jpeg_quality)
  192. if opt.initial_page < 1:
  193. raise ValidationError(_(
  194. "The initial page parameter must be strictly positive "
  195. "(current value: %d)") % opt.initial_page)
  196. if opt.pdfa and opt.cross_doc_link_action == '1':
  197. raise ValidationError(_(
  198. "The PDF/A option is not compatible with "
  199. "'Cross-document Links' = "
  200. "'Open with PDF Reader Application'."))
  201. if opt.magnification == '4' and (opt.zoom < 50 or opt.zoom > 1600):
  202. raise ValidationError(_(
  203. "The value of the zoom factor must be between 50 and 1600 "
  204. "(current value: %d)") % opt.zoom)
  205. @api.onchange('encrypt')
  206. def encrypt_change(self):
  207. if not self.encrypt:
  208. self.document_password = False
  209. @api.onchange('restrict_permissions')
  210. def restrict_permissions_change(self):
  211. if not self.restrict_permissions:
  212. self.permission_password = False
  213. @api.onchange('pdfa')
  214. def pdfa_change(self):
  215. if self.pdfa:
  216. self.pdf_form = False
  217. self.encrypt = False
  218. self.restrict_permissions = False
  219. def odoo2libreoffice_options(self):
  220. self.ensure_one()
  221. options = {}
  222. # GENERAL TAB
  223. if self.image_compression == 'lossless':
  224. options['UseLosslessCompression'] = True
  225. else:
  226. options['UseLosslessCompression'] = False
  227. options['Quality'] = self.image_jpeg_quality
  228. if self.image_reduce_resolution != 'none':
  229. options['ReduceImageResolution'] = True
  230. options['MaxImageResolution'] = int(self.image_reduce_resolution)
  231. else:
  232. options['ReduceImageResolution'] = False
  233. if self.watermark and self.watermark_text:
  234. options['Watermark'] = self.watermark_text
  235. if self.pdfa:
  236. options['SelectPdfVersion'] = 1
  237. options['UseTaggedPDF'] = self.tagged_pdf
  238. else:
  239. options['SelectPdfVersion'] = 0
  240. if self.pdf_form and self.pdf_form_format and not self.pdfa:
  241. options['ExportFormFields'] = True
  242. options['FormsType'] = int(self.pdf_form_format)
  243. options['AllowDuplicateFieldNames'] = self.pdf_form_allow_duplicate
  244. else:
  245. options['ExportFormFields'] = False
  246. options.update({
  247. 'ExportBookmarks': self.export_bookmarks,
  248. 'ExportPlaceholders': self.export_placeholders,
  249. 'ExportNotes': self.export_comments,
  250. 'ExportHiddenSlides': self.export_hidden_slides,
  251. })
  252. # INITIAL VIEW TAB
  253. options.update({
  254. 'InitialView': int(self.initial_view),
  255. 'InitialPage': self.initial_page,
  256. 'Magnification': int(self.magnification),
  257. 'PageLayout': int(self.page_layout),
  258. })
  259. if self.magnification == '4':
  260. options['Zoom'] = self.zoom
  261. # USER INTERFACE TAB
  262. options.update({
  263. 'ResizeWindowToInitialPage': self.resize_windows_initial_page,
  264. 'CenterWindow': self.center_window,
  265. 'OpenInFullScreenMode': self.open_fullscreen,
  266. 'DisplayPDFDocumentTitle': self.display_document_title,
  267. 'HideViewerMenubar': self.hide_menubar,
  268. 'HideViewerToolbar': self.hide_toolbar,
  269. 'HideViewerWindowControls': self.hide_window_controls,
  270. })
  271. if self.open_bookmark_levels:
  272. options['OpenBookmarkLevels'] = int(self.open_bookmark_levels)
  273. # LINKS TAB
  274. options.update({
  275. 'ExportBookmarksToPDFDestination':
  276. self.export_bookmarks_named_dest,
  277. 'ConvertOOoTargetToPDFTarget': self.convert_doc_ref_to_pdf_target,
  278. 'ExportLinksRelativeFsys': self.export_filesystem_urls,
  279. 'PDFViewSelection': int(self.cross_doc_link_action),
  280. })
  281. # SECURITY TAB
  282. if not self.pdfa:
  283. if self.encrypt and self.document_password:
  284. options['EncryptFile'] = True
  285. options['DocumentOpenPassword'] = self.document_password
  286. if self.restrict_permissions and self.permission_password:
  287. options.update({
  288. 'RestrictPermissions': True,
  289. 'PermissionPassword': self.permission_password,
  290. 'Printing': int(self.printing),
  291. 'Changes': int(self.changes),
  292. 'EnableCopyingOfContent': self.content_copying_allowed,
  293. 'EnableTextAccessForAccessibilityTools':
  294. self.text_access_accessibility_tools_allowed,
  295. })
  296. logger.debug(
  297. 'Py3o PDF options ID %s converted to %s', self.id, options)
  298. return options