dangerzone/dangerzone/gui/logic.py
deeplow 7e42994f81
Prevent user from adding files from multiple dirs
Allowing this would lead to several UI edge-cases related to where the
files would be saved. Avoiding this is the easiest solution at the
moment.

In the future we should consider other options.
2022-11-30 12:49:20 +00:00

185 lines
6 KiB
Python

import logging
import os
import pipes
import platform
import shlex
import subprocess
from pathlib import Path
from typing import Dict
from colorama import Fore
from PySide2 import QtCore, QtGui, QtWidgets
if platform.system() == "Linux":
from xdg.DesktopEntry import DesktopEntry
from ..logic import DangerzoneCore
from ..settings import Settings
from ..util import get_resource_path
log = logging.getLogger(__name__)
class DangerzoneGui(DangerzoneCore):
"""
Singleton of shared state / functionality for the GUI and core app logic
"""
def __init__(self, app: QtWidgets.QApplication) -> None:
super().__init__()
# Qt app
self.app = app
# Only one output dir is supported in the GUI
self.output_dir: str = ""
# Preload font
self.fixed_font = QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.FixedFont)
# Preload list of PDF viewers on computer
self.pdf_viewers = self._find_pdf_viewers()
# Are we done waiting (for Docker Desktop to be installed, or for container to install)
self.is_waiting_finished = False
def get_window_icon(self) -> QtGui.QIcon:
if platform.system() == "Windows":
path = get_resource_path("dangerzone.ico")
else:
path = get_resource_path("icon.png")
return QtGui.QIcon(path)
def open_pdf_viewer(self, filename: str) -> None:
if platform.system() == "Darwin":
# Open in Preview
args = ["open", "-a", "Preview.app", filename]
# Run
args_str = " ".join(pipes.quote(s) for s in args)
log.info(Fore.YELLOW + "> " + Fore.CYAN + args_str)
subprocess.run(args)
elif platform.system() == "Windows":
os.startfile(Path(filename)) # type: ignore [attr-defined]
elif platform.system() == "Linux":
# Get the PDF reader command
args = shlex.split(self.pdf_viewers[self.settings.get("open_app")])
# %f, %F, %u, and %U are filenames or URLS -- so replace with the file to open
for i in range(len(args)):
if (
args[i] == "%f"
or args[i] == "%F"
or args[i] == "%u"
or args[i] == "%U"
):
args[i] = filename
# Open as a background process
args_str = " ".join(pipes.quote(s) for s in args)
log.info(Fore.YELLOW + "> " + Fore.CYAN + args_str)
subprocess.Popen(args)
def _find_pdf_viewers(self) -> Dict[str, str]:
pdf_viewers: Dict[str, str] = {}
if platform.system() == "Linux":
# Find all .desktop files
for search_path in [
"/usr/share/applications",
"/usr/local/share/applications",
os.path.expanduser("~/.local/share/applications"),
]:
try:
for filename in os.listdir(search_path):
full_filename = os.path.join(search_path, filename)
if os.path.splitext(filename)[1] == ".desktop":
# See which ones can open PDFs
desktop_entry = DesktopEntry(full_filename)
if (
"application/pdf" in desktop_entry.getMimeTypes()
and desktop_entry.getName() != "dangerzone"
):
pdf_viewers[
desktop_entry.getName()
] = desktop_entry.getExec()
except FileNotFoundError:
pass
return pdf_viewers
class Alert(QtWidgets.QDialog):
def __init__(
self,
dangerzone: DangerzoneGui,
message: str,
ok_text: str = "Ok",
has_cancel: bool = True,
extra_button_text: str = None,
) -> None:
super(Alert, self).__init__()
self.dangerzone = dangerzone
self.setWindowTitle("dangerzone")
self.setWindowIcon(self.dangerzone.get_window_icon())
self.setModal(True)
flags = (
QtCore.Qt.CustomizeWindowHint
| QtCore.Qt.WindowTitleHint
| QtCore.Qt.WindowSystemMenuHint
| QtCore.Qt.WindowCloseButtonHint
| QtCore.Qt.WindowStaysOnTopHint
)
self.setWindowFlags(flags)
logo = QtWidgets.QLabel()
logo.setPixmap(
QtGui.QPixmap.fromImage(QtGui.QImage(get_resource_path("icon.png")))
)
label = QtWidgets.QLabel()
label.setText(message)
label.setWordWrap(True)
message_layout = QtWidgets.QHBoxLayout()
message_layout.addWidget(logo)
message_layout.addSpacing(10)
message_layout.addWidget(label, stretch=1)
ok_button = QtWidgets.QPushButton(ok_text)
ok_button.clicked.connect(self.clicked_ok)
if extra_button_text:
extra_button = QtWidgets.QPushButton(extra_button_text)
extra_button.clicked.connect(self.clicked_extra)
buttons_layout = QtWidgets.QHBoxLayout()
buttons_layout.addStretch()
buttons_layout.addWidget(ok_button)
if extra_button_text:
buttons_layout.addWidget(extra_button)
if has_cancel:
cancel_button = QtWidgets.QPushButton("Cancel")
cancel_button.clicked.connect(self.clicked_cancel)
buttons_layout.addWidget(cancel_button)
layout = QtWidgets.QVBoxLayout()
layout.addLayout(message_layout)
layout.addSpacing(10)
layout.addLayout(buttons_layout)
self.setLayout(layout)
def clicked_ok(self) -> None:
self.done(QtWidgets.QDialog.Accepted)
def clicked_extra(self) -> None:
self.done(2)
def clicked_cancel(self) -> None:
self.done(QtWidgets.QDialog.Rejected)
def launch(self) -> int:
return self.exec_()