Start making settings widget

This commit is contained in:
Micah Lee 2020-01-07 14:21:39 -08:00
parent acf46980f3
commit b527776e28
No known key found for this signature in database
GPG key ID: 403C2657CD994F73
7 changed files with 371 additions and 98 deletions

View file

@ -25,22 +25,7 @@ def main(filename):
# Common object # Common object
common = Common() common = Common()
# Main window if filename != "":
main_window = MainWindow(app, common)
# If a filename wasn't passed in, get with with a dialog
if filename == "":
filename = QtWidgets.QFileDialog.getOpenFileName(
main_window,
"Open document",
filter="Documents (*.pdf *.docx *.doc *.xlsx *.xls *.pptx *.ppt *.odt *.fodt *.ods *.fods *.odp *.fodp *.odg *.fodg *.odf)",
)
if filename[0] == "":
print("No document was not selected")
return
filename = filename[0]
else:
# Validate filename # Validate filename
filename = os.path.abspath(os.path.expanduser(filename)) filename = os.path.abspath(os.path.expanduser(filename))
try: try:
@ -51,6 +36,8 @@ def main(filename):
except PermissionError: except PermissionError:
print("Permission denied") print("Permission denied")
return return
common.set_document_filename(filename)
main_window.start(filename) # Main window
main_window = MainWindow(app, common)
sys.exit(app.exec_()) sys.exit(app.exec_())

View file

@ -2,6 +2,7 @@ import sys
import os import os
import inspect import inspect
import tempfile import tempfile
from PyQt5 import QtGui
class Common(object): class Common(object):
@ -16,6 +17,176 @@ class Common(object):
print(f"pixel_dir is: {self.pixel_dir.name}") print(f"pixel_dir is: {self.pixel_dir.name}")
print(f"safe_dir is: {self.safe_dir.name}") print(f"safe_dir is: {self.safe_dir.name}")
self.document_filename = None
self.fixed_font = QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.FixedFont)
self.ocr_languages = {
"Afrikaans": "ar",
"Amharic": "amh",
"Arabic": "ara",
"Assamese": "asm",
"Azerbaijani": "aze",
"Azerbaijani (Cyrillic)": "aze_cyrl",
"Belarusian": "bel",
"Bengali": "ben",
"Tibetan Standard": "bod",
"Bosnian": "bos",
"Breton": "bre",
"Bulgarian": "bul",
"Catalan": "cat",
"Cebuano": "ceb",
"Czech": "ces",
"Chinese - Simplified": "chi_sim",
"Chinese - Simplified (vertical)": "chi_sim_vert",
"Chinese - Traditional": "chi_tra",
"Chinese - Traditional (vertical)": "chi_tra_vert",
"Cherokee": "chr",
"Corsican": "cos",
"Welsh": "cym",
"Danish": "dan",
"German": "deu",
"Divehi": "div",
"Dzongkha": "dzo",
"Greek": "ell",
"English": "eng",
"English, Middle (1100-1500)": "enm",
"Esperanto": "epo",
"Estonian": "est",
"Basque": "eus",
"Faroese": "fao",
"Persian": "fas",
"Filipino": "fil",
"Finnish": "fin",
"French": "fra",
"Frankish": "frk",
"French, Middle (ca.1400-1600)": "frm",
"Frisian (Western)": "fry",
"Gaelic (Scots)": "gla",
"Irish": "gle",
"Galician": "glg",
"Gujarati": "guj",
"Hatian": "hat",
"Hebrew": "heb",
"Hindi": "hin",
"Croatian": "hrv",
"Hungarian": "hun",
"Armenian": "hye",
"Inuktitut": "iku",
"Indonesian": "ind",
"Icelandic": "isl",
"Italian": "ita",
"Italian - Old": "ita_old",
"Javanese": "jav",
"Japanese": "jpn",
"Japanese (vertical)": "jpn_vert",
"Kannada": "kan",
"Georgian": "kat",
"Old Georgian": "kat_old",
"Kazakh": "kaz",
"Khmer": "khm",
"Kyrgyz": "kir",
"Korean": "kor",
"Korean (vertical)": "kor_vert",
"Kurdish (Arabic)": "kur_ara",
"Lao": "lao",
"Latin": "lat",
"Latvian": "lav",
"Lithuanian": "lit",
"Luxembourgish": "ltz",
"Malayalam": "mal",
"Marathi": "mar",
"Macedonian": "mkd",
"Maltese": "mlt",
"Mongolian": "mon",
"Maori": "mri",
"Malay": "msa",
"Burmese": "mya",
"Nepali": "nep",
"Dutch": "nld",
"Norwegian": "nor",
"Occitan (post 1500)": "oci",
"Oriya": "ori",
"script and orientation": "osd",
"Punjabi": "pan",
"Polish": "pol",
"Portuguese": "por",
"Pashto": "pus",
"Quechua": "que",
"Romanian": "ron",
"Russian": "rus",
"Sanskrit": "san",
"Sinhala": "sin",
"Slovakian": "slk",
"Slovenian": "slv",
"Sindhi": "snd",
"Spanish": "spa",
"Spanish, Castilian - Old": "spa_old",
"Albanian": "sqi",
"Serbian": "srp",
"Serbian (Latin)": "srp_latn",
"Sundanese": "sun",
"Swahili": "swa",
"Swedish": "swe",
"Syriac": "syr",
"Tamil": "tam",
"Tatar": "tat",
"Telugu": "tel",
"Tajik": "tgk",
"Thai": "tha",
"Tigrinya": "tir",
"Tonga": "ton",
"Turkish": "tur",
"Uyghur": "uig",
"Ukrainian": "ukr",
"Urdu": "urd",
"Uzbek": "uzb",
"Uzbek (Cyrillic)": "uzb_cyrl",
"Vietnamese": "vie",
"Yiddish": "yid",
"Yoruba": "yor",
"Arabic script": "Arabic",
"Armenian script": "Armenian",
"Bengali script": "Bengali",
"Canadian Aboriginal script": "Canadian_Aboriginal",
"Cherokee script": "Cherokee",
"Cyrillic script": "Cyrillic",
"Devanagari script": "Devanagari",
"Ethiopic script": "Ethiopic",
"Fraktur script": "Fraktur",
"Georgian script": "Georgian",
"Greek script": "Greek",
"Gujarati script": "Gujarati",
"Gurmukhi script": "Gurmukhi",
"Han - Simplified script": "HanS",
"Han - Simplified (vertical) script": "HanS_vert",
"Han - Traditional script": "HanT",
"Han - Traditional (vertical) script": "HanT_vert",
"Hangul script": "Hangul",
"Hangul (vertical) script": "Hangul_vert",
"Hebrew script": "Hebrew",
"Japanese script": "Japanese",
"Japanese (vertical) script": "Japanese_vert",
"Kannada script": "Kannada",
"Khmer script": "Khmer",
"Lao script": "Lao",
"Latin script": "Latin",
"Malayalam script": "Malayalam",
"Myanmar script": "Myanmar",
"Oriya (Odia) script": "Oriya",
"Sinhala script": "Sinhala",
"Syriac script": "Syriac",
"Tamil script": "Tamil",
"Telugu script": "Telugu",
"Thaana script": "Thaana",
"Thai script": "Thai",
"Tibetan script": "Tibetan",
"Vietnamese script": "Vietnamese",
}
def set_document_filename(self, filename):
self.document_filename = filename
def get_resource_path(self, filename): def get_resource_path(self, filename):
if getattr(sys, "dangerzone_dev", False): if getattr(sys, "dangerzone_dev", False):
# Look for resources directory relative to python file # Look for resources directory relative to python file

View file

@ -2,7 +2,8 @@ import shutil
import os import os
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from .tasks import PullImageTask, BuildContainerTask, ConvertToPixels, ConvertToPDF from .settings_widget import SettingsWidget
from .tasks_widget import TasksWidget
class MainWindow(QtWidgets.QMainWindow): class MainWindow(QtWidgets.QMainWindow):
@ -15,94 +16,43 @@ class MainWindow(QtWidgets.QMainWindow):
self.setMinimumWidth(500) self.setMinimumWidth(500)
self.setMinimumHeight(400) self.setMinimumHeight(400)
self.task_label = QtWidgets.QLabel() # Header
self.task_label.setAlignment(QtCore.Qt.AlignCenter) logo = QtWidgets.QLabel()
self.task_label.setStyleSheet("QLabel { font-weight: bold; font-size: 20px; }") logo.setPixmap(
QtGui.QPixmap.fromImage(
font = QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.FixedFont) QtGui.QImage(self.common.get_resource_path("icon.png"))
self.task_details = QtWidgets.QLabel()
self.task_details.setStyleSheet(
"QLabel { background-color: #ffffff; font-size: 12px; padding: 10px; }"
) )
self.task_details.setFont(font)
self.task_details.setAlignment(QtCore.Qt.AlignTop)
self.details_scrollarea = QtWidgets.QScrollArea()
self.details_scrollarea.setWidgetResizable(True)
self.details_scrollarea.setWidget(self.task_details)
self.details_scrollarea.verticalScrollBar().rangeChanged.connect(
self.scroll_to_bottom
) )
header_label = QtWidgets.QLabel("dangerzone")
header_label.setFont(self.common.fixed_font)
header_label.setStyleSheet("QLabel { font-weight: bold; font-size: 50px; }")
header_layout = QtWidgets.QHBoxLayout()
header_layout.addStretch()
header_layout.addWidget(logo)
header_layout.addSpacing(10)
header_layout.addWidget(header_label)
header_layout.addStretch()
# Settings
self.settings_widget = SettingsWidget(self.common)
self.settings_widget.show()
# Tasks
self.tasks_widget = TasksWidget(self.common)
self.tasks_widget.hide()
# Layout
layout = QtWidgets.QVBoxLayout() layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.task_label) layout.addLayout(header_layout)
layout.addWidget(self.details_scrollarea, stretch=1) layout.addWidget(self.settings_widget, stretch=1)
layout.addWidget(self.tasks_widget, stretch=1)
central_widget = QtWidgets.QWidget() central_widget = QtWidgets.QWidget()
central_widget.setLayout(layout) central_widget.setLayout(layout)
self.setCentralWidget(central_widget) self.setCentralWidget(central_widget)
self.tasks = [PullImageTask, BuildContainerTask, ConvertToPixels, ConvertToPDF]
def start(self, filename):
print(f"Input document: {filename}")
self.common.document_filename = filename
self.show() self.show()
self.next_task()
def next_task(self):
if len(self.tasks) == 0:
self.save_safe_pdf()
return
self.task_details.setText("")
self.current_task = self.tasks.pop(0)(self.common)
self.current_task.update_label.connect(self.update_label)
self.current_task.update_details.connect(self.update_details)
self.current_task.task_finished.connect(self.next_task)
self.current_task.task_failed.connect(self.task_failed)
self.current_task.start()
def update_label(self, s):
self.task_label.setText(s)
def update_details(self, s):
self.task_details.setText(s)
def task_failed(self, err):
self.task_label.setText("Task failed :(")
self.task_details.setWordWrap(True)
self.task_details.setText(
f"Directory with pixel data: {self.common.pixel_dir.name}\n\n{err}"
)
def save_safe_pdf(self):
suggested_filename = (
f"{os.path.splitext(self.common.document_filename)[0]}-safe.pdf"
)
filename = QtWidgets.QFileDialog.getSaveFileName(
self, "Save safe PDF", suggested_filename, filter="Documents (*.pdf)"
)
if filename[0] == "":
print("Save file dialog canceled")
else:
source_filename = f"{self.common.safe_dir.name}/safe-output-compressed.pdf"
dest_filename = filename[0]
shutil.move(source_filename, dest_filename)
# Clean up
self.common.pixel_dir.cleanup()
self.common.safe_dir.cleanup()
# Quit
self.app.quit()
def scroll_to_bottom(self, minimum, maximum):
self.details_scrollarea.verticalScrollBar().setValue(maximum)
def closeEvent(self, e): def closeEvent(self, e):
e.accept() e.accept()
self.app.quit() self.app.quit()

View file

@ -0,0 +1,79 @@
from PyQt5 import QtCore, QtGui, QtWidgets
class SettingsWidget(QtWidgets.QWidget):
def __init__(self, common):
super(SettingsWidget, self).__init__()
self.common = common
# Dangerous document selection
self.dangerous_doc_label = QtWidgets.QLabel()
self.dangerous_doc_label.hide()
self.dangerous_doc_button = QtWidgets.QPushButton(
"Select dangerous document ..."
)
self.dangerous_doc_button.setStyleSheet("QPushButton { font-weight: bold }")
dangerous_doc_layout = QtWidgets.QHBoxLayout()
dangerous_doc_layout.addWidget(self.dangerous_doc_label)
dangerous_doc_layout.addWidget(self.dangerous_doc_button)
dangerous_doc_layout.addStretch()
# Save safe version
self.save_checkbox = QtWidgets.QCheckBox("Save safe PDF")
self.save_lineedit = QtWidgets.QLineEdit()
self.save_lineedit.setReadOnly(True)
self.save_browse_button = QtWidgets.QPushButton("Save as...")
save_layout = QtWidgets.QHBoxLayout()
save_layout.addWidget(self.save_checkbox)
save_layout.addWidget(self.save_lineedit)
save_layout.addWidget(self.save_browse_button)
save_layout.addStretch()
# OCR document
self.ocr_checkbox = QtWidgets.QCheckBox("OCR document, language")
self.ocr_combobox = QtWidgets.QComboBox()
for k in self.common.ocr_languages:
self.ocr_combobox.addItem(k, QtCore.QVariant(self.common.ocr_languages[k]))
ocr_layout = QtWidgets.QHBoxLayout()
ocr_layout.addWidget(self.ocr_checkbox)
ocr_layout.addWidget(self.ocr_combobox)
ocr_layout.addStretch()
# Open safe document
self.open_checkbox = QtWidgets.QCheckBox("Open safe document")
self.open_combobox = QtWidgets.QComboBox()
open_layout = QtWidgets.QHBoxLayout()
open_layout.addWidget(self.open_checkbox)
open_layout.addWidget(self.open_combobox)
open_layout.addStretch()
# Update container
self.update_checkbox = QtWidgets.QCheckBox("Update container")
update_layout = QtWidgets.QHBoxLayout()
update_layout.addWidget(self.update_checkbox)
update_layout.addStretch()
# Button
self.button_start = QtWidgets.QPushButton("Convert to Save Document")
self.button_start.setStyleSheet(
"QPushButton { font-size: 16px; font-weight: bold; padding: 10px; }"
)
button_layout = QtWidgets.QHBoxLayout()
button_layout.addStretch()
button_layout.addWidget(self.button_start)
button_layout.addStretch()
# Layout
layout = QtWidgets.QVBoxLayout()
layout.addLayout(dangerous_doc_layout)
layout.addLayout(save_layout)
layout.addLayout(ocr_layout)
layout.addLayout(open_layout)
layout.addLayout(update_layout)
layout.addLayout(button_layout)
layout.addStretch()
self.setLayout(layout)

View file

@ -0,0 +1,88 @@
from PyQt5 import QtCore, QtGui, QtWidgets
from .tasks import PullImageTask, BuildContainerTask, ConvertToPixels, ConvertToPDF
class TasksWidget(QtWidgets.QWidget):
def __init__(self, common):
super(TasksWidget, self).__init__()
self.common = common
self.task_label = QtWidgets.QLabel()
self.task_label.setAlignment(QtCore.Qt.AlignCenter)
self.task_label.setStyleSheet("QLabel { font-weight: bold; font-size: 20px; }")
self.task_details = QtWidgets.QLabel()
self.task_details.setStyleSheet(
"QLabel { background-color: #ffffff; font-size: 12px; padding: 10px; }"
)
self.task_details.setFont(self.common.fixed_font)
self.task_details.setAlignment(QtCore.Qt.AlignTop)
self.details_scrollarea = QtWidgets.QScrollArea()
self.details_scrollarea.setWidgetResizable(True)
self.details_scrollarea.setWidget(self.task_details)
self.details_scrollarea.verticalScrollBar().rangeChanged.connect(
self.scroll_to_bottom
)
self.tasks = [PullImageTask, BuildContainerTask, ConvertToPixels, ConvertToPDF]
def start(self, filename):
print(f"Input document: {filename}")
self.common.set_document_filename(filename)
self.show()
self.next_task()
def next_task(self):
if len(self.tasks) == 0:
self.save_safe_pdf()
return
self.task_details.setText("")
self.current_task = self.tasks.pop(0)(self.common)
self.current_task.update_label.connect(self.update_label)
self.current_task.update_details.connect(self.update_details)
self.current_task.task_finished.connect(self.next_task)
self.current_task.task_failed.connect(self.task_failed)
self.current_task.start()
def update_label(self, s):
self.task_label.setText(s)
def update_details(self, s):
self.task_details.setText(s)
def task_failed(self, err):
self.task_label.setText("Task failed :(")
self.task_details.setWordWrap(True)
self.task_details.setText(
f"Directory with pixel data: {self.common.pixel_dir.name}\n\n{err}"
)
def save_safe_pdf(self):
suggested_filename = (
f"{os.path.splitext(self.common.document_filename)[0]}-safe.pdf"
)
filename = QtWidgets.QFileDialog.getSaveFileName(
self, "Save safe PDF", suggested_filename, filter="Documents (*.pdf)"
)
if filename[0] == "":
print("Save file dialog canceled")
else:
source_filename = f"{self.common.safe_dir.name}/safe-output-compressed.pdf"
dest_filename = filename[0]
shutil.move(source_filename, dest_filename)
# Clean up
self.common.pixel_dir.cleanup()
self.common.safe_dir.cleanup()
# Quit
self.app.quit()
def scroll_to_bottom(self, minimum, maximum):
self.details_scrollarea.verticalScrollBar().setValue(maximum)

View file

@ -1,9 +1,7 @@
FROM ubuntu:18.04 FROM ubuntu:18.04
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y file poppler-utils imagemagick ghostscript tesseract-ocr libreoffice apt-get install -y file poppler-utils imagemagick ghostscript tesseract-ocr tesseract-ocr-all libreoffice
# TODO: when we support OCR in other languages, we need tesseract-ocr-all
# Fix imagemagick policy to allow writing PDFs # Fix imagemagick policy to allow writing PDFs
RUN sed -i '/rights="none" pattern="PDF"/c\<policy domain="coder" rights="read|write" pattern="PDF" />' /etc/ImageMagick-6/policy.xml RUN sed -i '/rights="none" pattern="PDF"/c\<policy domain="coder" rights="read|write" pattern="PDF" />' /etc/ImageMagick-6/policy.xml

BIN
share/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB