Merge pull request 'Add a configuration dialog, better output and PDF exporting' (#2) from configure-dialog into master

Reviewed-on: #2
This commit is contained in:
raoul 2021-08-08 00:39:30 +00:00
commit abd6d76b04
5 changed files with 545 additions and 17 deletions

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigureDialog</class>
<widget class="QDialog" name="ConfigureDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="configureLayout">
<item>
<widget class="QGroupBox" name="renderOptionsGroupBox">
<property name="title">
<string>Render Options</string>
</property>
<layout class="QFormLayout" name="renderOptionsLayout"/>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ConfigureDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ConfigureDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,338 @@
# -*- coding: utf-8 -*-
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
from chordpro.renderers.html import get_options, get_option_groups
from ukatali.util import coerce_bool, convert_units
SUPPORTED_SIZES = {
QtGui.QPageSize.A4: 'A4',
QtGui.QPageSize.A5: 'A5',
QtGui.QPageSize.B5: 'B5',
QtGui.QPageSize.B6: 'B6',
QtGui.QPageSize.Letter: 'Letter',
QtGui.QPageSize.Legal: 'Legal',
QtGui.QPageSize.ExecutiveStandard: 'Executive'
}
SUPPORTED_UNITS = {
QtGui.QPageSize.Millimeter: 'mm',
QtGui.QPageSize.Point: 'pt',
QtGui.QPageSize.Inch: 'in'
}
SUPPORTED_ORIENTATIONS = {
'Portrait': QtGui.QPageLayout.Portrait,
'Landscape': QtGui.QPageLayout.Landscape
}
class ConfigureDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.settings = QtCore.QSettings()
self.option_widgets = {}
self.option_values = {}
self.editor_values = {}
self.export_values = {}
self.setup_ui()
self.setup_options()
def setup_ui(self):
self.setObjectName('ConfigureDialog')
self.resize(600, 400)
self.configure_layout = QtWidgets.QVBoxLayout(self)
self.configure_layout.setObjectName("configure_layout")
self.category_layout = QtWidgets.QHBoxLayout()
self.category_layout.setObjectName('category_layout')
self.configure_layout.addLayout(self.category_layout)
self.category_list_widget = QtWidgets.QListWidget(self)
self.category_list_widget.setFixedWidth(100)
self.category_list_widget.addItems(['', '', '', ''])
self.category_list_widget.setObjectName('category_list_widget')
self.category_layout.addWidget(self.category_list_widget)
self.category_stack = QtWidgets.QStackedWidget(self)
self.category_stack.setObjectName('category_stack')
self.category_layout.addWidget(self.category_stack)
# General settings
self.general_page = QtWidgets.QWidget()
self.general_page.setObjectName('general_page')
self.category_stack.addWidget(self.general_page)
# Editor settings
self.editor_page = QtWidgets.QWidget()
self.editor_page.setObjectName('editor_page')
self.category_stack.addWidget(self.editor_page)
self.editor_layout = QtWidgets.QFormLayout(self.editor_page)
self.editor_layout.setObjectName('editor_layout')
self.editor_font_combobox = QtWidgets.QFontComboBox(self.editor_page)
self.editor_font_combobox.setFontFilters(QtWidgets.QFontComboBox.MonospacedFonts)
self.editor_font_combobox.setCurrentFont(QtGui.QFont('monospace'))
self.editor_font_combobox.setObjectName('editor_font_combobox')
self.editor_layout.addRow('Font', self.editor_font_combobox)
self.editor_size_spinbox = QtWidgets.QSpinBox(self.editor_page)
self.editor_size_spinbox.setValue(10)
self.editor_size_spinbox.setObjectName('editor_size_spinbox')
self.editor_layout.addRow('Size', self.editor_size_spinbox)
# Renderer settings
self.renderer_page = QtWidgets.QWidget()
self.renderer_page.setObjectName('renderer_page')
self.category_stack.addWidget(self.renderer_page)
self.render_layout = QtWidgets.QVBoxLayout(self.renderer_page)
self.render_options_combobox = QtWidgets.QComboBox(self.renderer_page)
self.render_options_combobox.setObjectName("render_options_combobox")
self.render_layout.addWidget(self.render_options_combobox)
self.render_options_stack = QtWidgets.QStackedWidget(self)
self.render_options_stack.setObjectName("render_options_stack")
self.render_layout.addWidget(self.render_options_stack)
# Export settings
self.export_page = QtWidgets.QWidget()
self.export_page.setObjectName('export_page')
self.category_stack.addWidget(self.export_page)
self.export_layout = QtWidgets.QFormLayout(self.export_page)
self.export_layout.setObjectName('export_layout')
self.export_size_combobox = QtWidgets.QComboBox(self.export_page)
for idx, (size_id, size_name) in enumerate(SUPPORTED_SIZES.items()):
self.export_size_combobox.addItem(size_name)
self.export_size_combobox.setItemData(idx, size_id)
self.export_size_combobox.setCurrentIndex(0)
self.export_size_combobox.setObjectName('export_size_combobox')
self.export_layout.addRow('Page size', self.export_size_combobox)
self.export_orientation_layout = QtWidgets.QHBoxLayout()
self.export_orientation_layout.setObjectName('export_orientation_layout')
self.export_orientation_portrait_radio = QtWidgets.QRadioButton(self.export_page)
self.export_orientation_portrait_radio.setChecked(True)
self.export_orientation_portrait_radio.setObjectName('export_orientation_portrait_radio')
self.export_orientation_layout.addWidget(self.export_orientation_portrait_radio)
self.export_orientation_landscape_radio = QtWidgets.QRadioButton(self.export_page)
self.export_orientation_landscape_radio.setObjectName('export_orientation_landscape_radio')
self.export_orientation_layout.addWidget(self.export_orientation_landscape_radio)
self.export_layout.addRow('Orientation', self.export_orientation_layout)
self.export_unit_combobox = QtWidgets.QComboBox(self.export_page)
for idx, (unit_id, unit_name) in enumerate(SUPPORTED_UNITS.items()):
self.export_unit_combobox.addItem(unit_name)
self.export_unit_combobox.setItemData(idx, unit_id)
self.export_unit_combobox.setCurrentIndex(0)
self.export_unit_combobox.setObjectName('export_unit_combobox')
self.export_layout.addRow('Unit', self.export_unit_combobox)
self.export_margin_top_spinbox = QtWidgets.QDoubleSpinBox(self.export_page)
self.export_margin_top_spinbox.setValue(20)
self.export_margin_top_spinbox.setSuffix(self.export_unit_combobox.currentText())
self.export_margin_top_spinbox.setObjectName('export_margin_top_spinbox')
self.export_layout.addRow('Top margin', self.export_margin_top_spinbox)
self.export_margin_left_spinbox = QtWidgets.QDoubleSpinBox(self.export_page)
self.export_margin_left_spinbox.setValue(20)
self.export_margin_left_spinbox.setSuffix(self.export_unit_combobox.currentText())
self.export_margin_left_spinbox.setObjectName('export_margin_left_spinbox')
self.export_layout.addRow('Left margin', self.export_margin_left_spinbox)
self.export_margin_right_spinbox = QtWidgets.QDoubleSpinBox(self.export_page)
self.export_margin_right_spinbox.setValue(20)
self.export_margin_right_spinbox.setSuffix(self.export_unit_combobox.currentText())
self.export_margin_right_spinbox.setObjectName('export_margin_right_spinbox')
self.export_layout.addRow('Right margin', self.export_margin_right_spinbox)
self.export_margin_bottom_spinbox = QtWidgets.QDoubleSpinBox(self.export_page)
self.export_margin_bottom_spinbox.setValue(20)
self.export_margin_bottom_spinbox.setSuffix(self.export_unit_combobox.currentText())
self.export_margin_bottom_spinbox.setObjectName('export_margin_bottom_spinbox')
self.export_layout.addRow('Bottom margin', self.export_margin_bottom_spinbox)
# Buttons
self.button_box = QtWidgets.QDialogButtonBox(self)
self.button_box.setOrientation(QtCore.Qt.Horizontal)
self.button_box.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel |
QtWidgets.QDialogButtonBox.Ok)
self.button_box.setObjectName("button_box")
self.configure_layout.addWidget(self.button_box)
self.retranslate_ui()
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
self.category_list_widget.currentRowChanged.connect(self.category_stack.setCurrentIndex)
self.render_options_combobox.activated.connect(self.render_options_stack.setCurrentIndex)
on_editor_font_changed = partial(self._set_editor_value, 'font')
self.editor_font_combobox.currentFontChanged.connect(on_editor_font_changed)
on_editor_size_changed = partial(self._set_editor_value, 'size')
self.editor_size_spinbox.valueChanged.connect(on_editor_size_changed)
on_export_size_changed = partial(self._set_export_value, 'page_size')
self.export_size_combobox.currentIndexChanged.connect(on_export_size_changed)
self.export_unit_combobox.currentIndexChanged.connect(self.on_export_unit_changed)
on_export_margin_left_changed = partial(self._set_export_value, 'margin_left')
self.export_margin_left_spinbox.valueChanged.connect(on_export_margin_left_changed)
on_export_margin_right_changed = partial(self._set_export_value, 'margin_right')
self.export_margin_right_spinbox.valueChanged.connect(on_export_margin_right_changed)
on_export_margin_top_changed = partial(self._set_export_value, 'margin_top')
self.export_margin_top_spinbox.valueChanged.connect(on_export_margin_top_changed)
on_export_margin_bottom_changed = partial(self._set_export_value, 'margin_bottom')
self.export_margin_bottom_spinbox.valueChanged.connect(on_export_margin_bottom_changed)
on_export_orientation_portait_clicked = partial(self._set_export_value, 'orientation')
self.export_orientation_portrait_radio.toggled.connect(on_export_orientation_portait_clicked)
def retranslate_ui(self):
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("ConfigureDialog", "Configure"))
self.category_list_widget.item(0).setText(_translate('ConfigureDialog', 'General'))
self.category_list_widget.item(1).setText(_translate('ConfigureDialog', 'Editor'))
self.category_list_widget.item(2).setText(_translate('ConfigureDialog', 'Render'))
self.category_list_widget.item(3).setText(_translate('ConfigureDialog', 'PDF'))
self.export_orientation_portrait_radio.setText(_translate('ConfigureDialog', 'Portrait'))
self.export_orientation_landscape_radio.setText(_translate('ConfigureDialog', 'Landscape'))
def _set_option_value(self, name, value):
"""Set an option value"""
self.option_values[name] = value
def _set_editor_value(self, name, value):
"""Set an editor value"""
self.editor_values[name] = value
def _set_export_value(self, name, value):
"""Set an export value"""
if name == 'page_size':
value = self.export_size_combobox.itemData(value)
elif name == 'units':
value = self.export_unit_combobox.itemData(value)
elif name == 'orientation':
value = QtGui.QPageLayout.Portrait if value else QtGui.QPageLayout.Landscape
self.export_values[name] = value
def setup_options(self):
for group in get_option_groups():
pretty_group = group.replace('_', ' ').title()
self.render_options_combobox.addItem(pretty_group)
page_widget = QtWidgets.QWidget()
page_layout = QtWidgets.QFormLayout(page_widget)
for name, details in get_options(group).items():
pretty_name = name.replace(group, '').replace('_', ' ').title()
self.option_values[name] = details['default']
widget = None
set_value = partial(self._set_option_value, name)
if details["type"] is int:
widget = QtWidgets.QSpinBox(page_widget)
if details['default']:
widget.setValue(details['default'])
widget.valueChanged.connect(set_value)
elif details["type"] is bool:
widget = QtWidgets.QCheckBox(page_widget)
widget.setChecked(coerce_bool(details['default']))
widget.toggled.connect(set_value)
elif 'font' in name:
widget = QtWidgets.QFontComboBox(page_widget)
if details['default']:
widget.setFont(QtGui.QFont(details['default']))
widget.currentFontChanged.connect(set_value)
else:
widget = QtWidgets.QLineEdit(page_widget)
if details['default']:
widget.setText(details['default'])
widget.textChanged.connect(set_value)
if widget:
widget.setObjectName(name)
self.option_widgets[name] = widget
page_layout.addRow(pretty_name, widget)
if details['description']:
label = QtWidgets.QLabel(page_widget)
label.setText(details['description'])
page_layout.addRow('', label)
self.render_options_stack.addWidget(page_widget)
def load_settings(self):
"""Load the settings"""
# Editor settings
self.settings.beginGroup('editor')
if self.settings.contains('font'):
value = QtGui.QFont(self.settings.value('font'))
self.editor_values['font'] = value
self.editor_font_combobox.setCurrentFont(value)
if self.settings.contains('size'):
value = int(self.settings.value('size'))
self.editor_values['size'] = value
self.editor_size.setValue(value)
self.settings.endGroup()
# Renderer settings
self.settings.beginGroup('render')
for name, details in get_options().items():
if self.settings.contains(name):
value = self.settings.value(name)
if value is None:
continue
if details['type'] is int:
value = int(value)
self.option_widgets[name].setValue(value)
elif details['type'] is bool:
value = coerce_bool(value)
self.option_widgets[name].setChecked(value)
elif 'font' in name:
value = QtGui.QFont(value)
self.option_widgets[name].setCurrentFont(value)
else:
self.option_widgets[name].setText(value)
self.option_values[name] = value
self.settings.endGroup()
# PDF settings
self.settings.beginGroup('export')
if self.settings.contains('page_size'):
value = int(self.settings.value('page_size'))
self.export_values['page_size'] = value
self.export_size_combobox.setCurrentText(SUPPORTED_SIZES[value])
if self.settings.contains('unit'):
value = int(self.settings.value('unit'))
self.export_values['unit'] = value
self.export_unit_combobox.setCurrentText(SUPPORTED_UNITS[value])
if self.settings.contains('orientation'):
value = int(self.settings.value('orientation'))
self.export_values['orientation'] = value
self.export_orientation_portrait_radio.setChecked(value == QtGui.QPageLayout.Portrait)
margins = [
('margin_left', self.export_margin_left_spinbox),
('margin_right', self.export_margin_right_spinbox),
('margin_top', self.export_margin_top_spinbox),
('margin_bottom', self.export_margin_bottom_spinbox),
]
for name, spinbox in margins:
if self.settings.contains(name):
value = float(self.settings.value(name))
self.export_values[name] = value
spinbox.setValue(value)
self.settings.endGroup()
def save_settings(self):
"""Save the settings"""
# Editor settings
self.settings.beginGroup('editor')
for name, value in self.editor_values.items():
if isinstance(value, QtGui.QFont):
value = value.family()
self.settings.setValue(name, value)
self.settings.endGroup()
# Renderer settings
self.settings.beginGroup('render')
for name, value in self.option_values.items():
if isinstance(value, QtGui.QFont):
value = value.family()
self.settings.setValue(name, value)
self.settings.endGroup()
# Export settings
self.settings.beginGroup('export')
for name, value in self.export_values.items():
self.settings.setValue(name, value)
self.settings.endGroup()
def exec(self):
"""Execute the dialog"""
self.load_settings()
return super().exec()
def accept(self):
"""The user clicked the "OK" button"""
self.save_settings()
return super().accept()
def on_export_unit_changed(self, value):
self._set_export_value('unit', self.export_unit_combobox.itemData(value))
new_suffix = self.export_unit_combobox.itemText(value)
for spinbox in [self.export_margin_bottom_spinbox, self.export_margin_left_spinbox,
self.export_margin_right_spinbox, self.export_margin_top_spinbox]:
old_suffix = spinbox.suffix()
spinbox.setSuffix(new_suffix)
spinbox.setValue(convert_units(spinbox.value(), old_suffix, new_suffix))
if new_suffix == 'in':
spinbox.setSingleStep(0.1)
else:
spinbox.setSingleStep(1.0)

View File

@ -127,7 +127,7 @@ class ChordProLexer(Qsci.QsciLexerCustom):
def styleText(self, start, end): def styleText(self, start, end):
"""Style the text""" """Style the text"""
keywords = ['chorus'] + \ keywords = ['verse', 'chorus', 'bridge'] + \
[d for t in KNOWN_DIRECTIVES for d in t] + \ [d for t in KNOWN_DIRECTIVES for d in t] + \
['start_of_' + vt for vt in KNOWN_VERSE_TYPES] + \ ['start_of_' + vt for vt in KNOWN_VERSE_TYPES] + \
['end_of_' + vt for vt in KNOWN_VERSE_TYPES] ['end_of_' + vt for vt in KNOWN_VERSE_TYPES]

View File

@ -1,17 +1,25 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
from pathlib import Path from pathlib import Path
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets, Qsci
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets, Qsci, QtPrintSupport
from chordpro import Song from chordpro import Song
from chordpro.renderers.html import render from chordpro.renderers.html import render, get_options
from ukatali.configuredialog import ConfigureDialog
from ukatali.lexer import ChordProLexer from ukatali.lexer import ChordProLexer
from ukatali.util import coerce_bool
CHORDPRO_FILTERS = 'ChordPro files (*.txt *.cho *.chordpro *.chopro);;All files (*)'
class MainWindow(QtWidgets.QMainWindow): class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.setup_ui() self.setup_ui()
self.settings = QtCore.QSettings()
self.filename = None self.filename = None
self.configure_dialog = ConfigureDialog(self)
def setup_ui(self): def setup_ui(self):
self.setObjectName('MainWindow') self.setObjectName('MainWindow')
@ -168,11 +176,14 @@ class MainWindow(QtWidgets.QMainWindow):
self.cut_action.triggered.connect(self.file_editor.cut) self.cut_action.triggered.connect(self.file_editor.cut)
self.copy_action.triggered.connect(self.file_editor.copy) self.copy_action.triggered.connect(self.file_editor.copy)
self.paste_action.triggered.connect(self.file_editor.paste) self.paste_action.triggered.connect(self.file_editor.paste)
# QtCore.QMetaObject.connectSlotsByName(self)
self.open_action.triggered.connect(self.on_open_clicked) self.open_action.triggered.connect(self.on_open_clicked)
self.save_action.triggered.connect(self.on_save_clicked) self.save_action.triggered.connect(self.on_save_clicked)
self.save_as_action.triggered.connect(self.on_save_as_clicked) self.save_as_action.triggered.connect(self.on_save_as_clicked)
self.export_action.triggered.connect(self.on_export_clicked)
self.print_action.triggered.connect(self.on_print_clicked)
self.configure_action.triggered.connect(self.on_configure_clicked)
self.file_editor.textChanged.connect(self.on_text_changed) self.file_editor.textChanged.connect(self.on_text_changed)
self.preview_view.page().pdfPrintingFinished.connect(self.on_pdf_finished)
def retranslate_ui(self): def retranslate_ui(self):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
@ -226,12 +237,11 @@ class MainWindow(QtWidgets.QMainWindow):
def on_open_clicked(self): def on_open_clicked(self):
"""Open the file""" """Open the file"""
if QtCore.QSettings().value('files/last-directory'): if self.settings.value('files/last-directory'):
last_directory = QtCore.QSettings().value('files/last-directory') last_directory = self.settings.value('files/last-directory')
else: else:
last_directory = '' last_directory = ''
filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', last_directory, filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', last_directory, filter=CHORDPRO_FILTERS)
filter='All files *')
if isinstance(filename, tuple): if isinstance(filename, tuple):
filename = filename[0] filename = filename[0]
if not filename: if not filename:
@ -240,7 +250,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.filename = filename self.filename = filename
file_path = Path(filename) file_path = Path(filename)
if file_path.exists(): if file_path.exists():
QtCore.QSettings().setValue('files/last-directory', str(file_path.parent)) self.settings.setValue('files/last-directory', str(file_path.parent))
self.file_editor.setText(file_path.open().read()) self.file_editor.setText(file_path.open().read())
def on_save_clicked(self): def on_save_clicked(self):
@ -253,25 +263,108 @@ class MainWindow(QtWidgets.QMainWindow):
def on_save_as_clicked(self): def on_save_as_clicked(self):
"""Save the file""" """Save the file"""
if QtCore.QSettings().value('files/last-directory'): if self.settings.value('files/last-directory'):
last_directory = QtCore.QSettings().value('files/last-directory') last_directory = self.settings.value('files/last-directory')
else: else:
last_directory = '' last_directory = ''
filename = QtWidgets.QFileDialog.getSaveFileName(self, 'Save file', last_directory, filename = QtWidgets.QFileDialog.getSaveFileName(self, 'Save file', last_directory, filter=CHORDPRO_FILTERS)
filter='All files *')
if isinstance(filename, tuple): if isinstance(filename, tuple):
filename = filename[0] filename = filename[0]
if not filename: if not filename:
return return
self.filename = filename self.filename = filename
QtCore.QSettings().setValue('files/last-directory', str(Path(filename).parent)) self.settings.setValue('files/last-directory', str(Path(filename).parent))
self.on_save_clicked() self.on_save_clicked()
def on_text_changed(self): def on_configure_clicked(self):
"""Update the preview when the text changes""" """Show the configuration dialog"""
if self.configure_dialog.exec() == QtWidgets.QDialog.Accepted and self.file_editor.text():
self.on_text_changed()
def _get_render_options(self):
"""Get all the render options from the settings"""
options = {}
self.settings.beginGroup('render')
for name, details in get_options().items():
if self.settings.contains(name):
value = self.settings.value(name)
if value is None:
continue
if details['type'] is int:
value = int(value)
elif details['type'] is bool:
value = coerce_bool(value)
options[name] = value
self.settings.endGroup()
return options
def _render_song(self, extra_styles=None):
"""Render the current song and return the HTML"""
options = self._get_render_options()
text = self.file_editor.text() text = self.file_editor.text()
song = Song() song = Song()
song.parse(text) song.parse(text)
html = render(song) if song.metadata.get('copyright'):
extra_styles = extra_styles or ''
extra_styles += os.linesep
extra_styles += '@page {{ @bottom-left {{ content: "{}"; }} }}'.format(song.metadata.get('copyright'))
return render(song, options, extra_styles)
def on_text_changed(self):
"""Update the preview when the text changes"""
html = self._render_song()
self.preview_view.setHtml(html) self.preview_view.setHtml(html)
def on_export_clicked(self):
"""Export the current song to PDF"""
if self.filename:
last_directory = str(Path(self.filename).with_suffix('.pdf'))
elif self.settings.value('files/last-directory'):
last_directory = self.settings.value('files/last-directory')
else:
last_directory = ''
filename = QtWidgets.QFileDialog.getSaveFileName(self, 'Export to PDF', last_directory,
filter='PDF files (.pdf)*')
if isinstance(filename, tuple):
filename = filename[0]
if not filename:
return
filename = Path(filename)
self.settings.setValue('files/last-directory', str(filename.parent))
# Load the page layout from settings
self.settings.beginGroup('export')
page_size = QtGui.QPageSize(int(self.settings.value('page_size', QtGui.QPageSize.A4)))
orientation = int(self.settings.value('orientation', QtGui.QPageLayout.Portrait))
unit = int(self.settings.value('unit', QtGui.QPageLayout.Millimeter))
margin_left = float(self.settings.value('margin_left', 20))
margin_right = float(self.settings.value('margin_right', 20))
margin_top = float(self.settings.value('margin_top', 20))
margin_bottom = float(self.settings.value('margin_bottom', 20))
self.settings.endGroup()
margins = QtCore.QMarginsF(QtCore.QMargins(margin_left, margin_top, margin_right, margin_bottom))
page_layout = QtGui.QPageLayout(page_size, orientation, margins, unit)
# Export to PDF
self.preview_view.page().printToPdf(str(filename), page_layout)
def on_pdf_finished(self, filename, is_success):
"""A slot to notify the user when the PDF is done"""
if is_success:
QtWidgets.QMessageBox.information(self, 'Export to PDF Successful',
'Successfully exported to "{}"'.format(Path(filename).name))
else:
QtWidgets.QMessageBox.critical(self, 'Error Exporting to PDF', 'There was an error while exporting to PDF')
def on_print_clicked(self):
"""Print the current song"""
def _on_print_finished(is_success):
print(is_success)
# print(QtPrintSupport.QPrinterInfo.defaultPrinterName())
# default_printer = QtPrintSupport.QPrinterInfo.defaultPrinter()
# print(default_printer)
printer = QtPrintSupport.QPrinter()
print_dialog = QtPrintSupport.QPrintDialog(printer, self.preview_view.page().view())
if print_dialog.exec() == QtWidgets.QDialog.Accepted:
self.preview_view.page().print(printer, _on_print_finished)

25
src/ukatali/util.py Normal file
View File

@ -0,0 +1,25 @@
def coerce_bool(value):
"""Coerce a value to be a boolean"""
if isinstance(value, str):
return value[0].lower() in ['t', 'y', '1']
else:
return bool(value)
def convert_units(value, old_unit, new_unit):
"""Convert a value from one unit to another"""
if old_unit == 'in' and new_unit == 'mm':
return value * 25.4
if old_unit == 'mm' and new_unit == 'in':
return value / 25.4
if old_unit == 'in' and new_unit == 'pt':
return value * 72.0
if old_unit == 'pt' and new_unit == 'in':
return value / 72.0
if old_unit == 'mm' and new_unit == 'pt':
# Convert to in and then to pt
return (value / 25.4) * 72.0
if old_unit == 'pt' and new_unit == 'mm':
# Convert to in and then to mm
return (value / 72.0) * 25.4
return value