import sys
import os
from JAK.Utils import Instance, bindings, getScreenGeometry
from JAK.KeyBindings import KeyPress
if bindings() == "PyQt5":
from PyQt5.QtCore import Qt, QSize, QUrl
from PyQt5.QtGui import QIcon, QPixmap, QImage
from PyQt5.QtWidgets import QMainWindow, QWidget, QMessageBox, QDesktopWidget, QSystemTrayIcon,\
QAction, QToolBar, QMenu, QMenuBar, QFileDialog, QLabel
else:
from PySide2.QtCore import Qt, QSize, QUrl
from PySide2.QtGui import QIcon, QPixmap, QImage
from PySide2.QtWidgets import QMainWindow, QWidget, QMessageBox, QDesktopWidget, QSystemTrayIcon,\
QAction, QToolBar, QMenu, QMenuBar, QFileDialog, QLabel
class SystemTrayIcon(QSystemTrayIcon):
def __init__(self, icon, app, config):
self.config = config
self.icon = icon
super(SystemTrayIcon, self).__init__(icon, parent=app)
self.setContextMenu(self.tray_menu())
self.show()
Create menu for the tray icon
def tray_menu(self):
self.menu = QMenu()
for item in self.config['window']["SystemTrayIcon"]:
try:
self.action = QAction(f"{item['title']}", self)
self.action.triggered.connect(item['action'])
if item['icon']:
self.action.setIcon(QIcon(QPixmap(item['icon'])))
self.menu.addAction(self.action)
except KeyError:
pass
return self.menu
class JWindow(QMainWindow):
def __init__(self, config):
super().__init__()
self.config = config
if config["window"]["backgroundImage"]:
Transparency must be set to True
self.label = QLabel(self)
self.setObjectName("JAKWindow")
self.setBackgroundImage(config["window"]["backgroundImage"])
self.video_corner = False
self.center = getScreenGeometry().center()
self.setWindowTitle(config['window']["title"])
self.setWindowFlags(config['window']["setFlags"])
self.setWAttribute(Qt.WA_DeleteOnClose)
for attr in config['window']["setAttribute"]:
self.setWAttribute(attr)
if config['window']["state"]:
self.setWindowState(config['window']["state"])
if config['window']["icon"] and os.path.isfile(config['window']["icon"]):
self.icon = QIcon(config['window']["icon"])
else:
print(f"icon not found: {config['window']['icon']}")
print("loading default icon:")
self.icon = QIcon.fromTheme("applications-internet")
view = Instance.retrieve("view")
if view:
self.view = view
self.setCentralWidget(self.view)
self.view.iconChanged.connect(self._icon_changed)
if config['webview']["online"]:
self.view.page().titleChanged.connect(self.status_message)
if config['window']["transparent"]:
Set Background Transparency
self.setWAttribute(Qt.WA_TranslucentBackground)
self.setAutoFillBackground(True)
if config['webview']["online"]:
Do not display toolbar or system tray offline
if config['window']["toolbar"]:
self.toolbar = JToolbar(self, config['window']["toolbar"], self.icon, config['window']["title"])
self.addToolBar(self.toolbar)
self.setMenuBar(Menu(self, config['window']["menus"]))
else:
if config['window']["showHelpMenu"]:
self.setMenuBar(Menu(self, config['window']["menus"]))
self.view.page().titleChanged.connect(self.status_message)
if config['window']["SystemTrayIcon"]:
self.system_tray = SystemTrayIcon(self.icon, self, config)
if config["debug"]:
self.showInspector()
self._set_icons()
def setBackgroundImage(self, image):
screen = getScreenGeometry()
pixmap = QPixmap(QImage(image)).scaled(screen.width(), screen.height(), Qt.KeepAspectRatioByExpanding)
self.label.setPixmap(pixmap)
self.label.setGeometry(0, 0, screen.width(), self.label.sizeHint().height())
def showInspector(self):
from JAK.DevTools import WebView, InspectorDock
self.inspector_dock = InspectorDock(self)
self.inspector_view = WebView(parent=self)
self.inspector_view.set_inspected_view(self.view)
self.inspector_dock.setWidget(self.inspector_view)
self.addDockWidget(Qt.TopDockWidgetArea, self.inspector_dock)
def hideInspector(self):
self.inspector_dock.hide()
def setWAttribute(self, attr):
self.setAttribute(attr, True)
def keyPressEvent(self, event):
KeyPress(event, self.config)
def _set_icons(self):
self.setWindowIcon(self.icon)
if self.config['window']["SystemTrayIcon"]:
self.system_tray.setIcon(self.icon)
def _icon_changed(self):
if not self.view.icon().isNull():
self.icon = self.view.icon()
self._set_icons()
def status_message(self):
Show status message
self.statusbar = self.statusBar()
self.statusbar.showMessage(self.view.page().title(), 10000)
def hide_show_bar(self):
if self.isFullScreen() or self.video_corner:
self.statusbar.hide()
if self.config['window']["toolbar"]:
self.toolbar.hide()
else:
self.statusbar.show()
if self.config['window']["toolbar"]:
self.toolbar.show()
def default_size(self, size: str):
Set to 70% screen size
screen = getScreenGeometry()
if size == "width":
return screen.width() * 2 / 3
elif size == "height":
return screen.height() * 2 / 3
def set_window_to_defaults(self):
self.window_original_position.moveCenter(self.center)
self.move(self.window_original_position.topLeft())
self.resize(self.default_size("width"), self.default_size("height"))
self.hide_show_bar()
self.setWindowFlags(Qt.Window)
self.show()
def set_window_to_corner(self):
self.move(self.window_original_position.bottomRight())
Set to 30% screen size
screen = getScreenGeometry()
self.resize(screen.width() * 0.7 / 2, screen.height() * 0.7 / 2)
self.hide_show_bar()
self.setWindowFlags(Qt.SplashScreen | Qt.WindowStaysOnTopHint)
self.show()
def corner_window(self):
if self.video_corner:
self.video_corner = False
self.set_window_to_defaults()
else:
self.video_corner = True
if self.isFullScreen():
self.showNormal()
self.set_window_to_corner()
class JToolbar(QToolBar):
def __init__(self, parent, toolbar, icon, title):
super(JToolbar, self).__init__(parent)
self.icon = icon
self.setMovable(False)
self.setContextMenuPolicy(Qt.PreventContextMenu)
self.setIconSize(QSize(32, 32))
self.about_title = "About"
if toolbar:
If a dict is passed generate buttons from dict
for btn in toolbar:
try:
if btn["icon"]:
item = QAction(QIcon(btn["icon"]), btn["name"], self)
except KeyError:
item = QAction(btn["name"], self)
item.triggered.connect(self._on_click(btn["url"]))
self.addAction(item)
def _on_click(self, url: str, title=""):
view = Instance.retrieve("view")
if url.startswith("https"):
return lambda: view.setUrl(QUrl(url))
else:
msg = url
return lambda: Dialog.information(self, title, msg)
class Menu(QMenuBar):
def __init__(self, parent, menus):
super(Menu, self).__init__(parent)
if menus:
for menu in menus:
if type(menu) is dict:
title = self.addMenu(menu["title"])
for entry in menu["entries"]:
submenu = QAction(entry[0], self)
title.addAction(submenu)
print(entry[1])
submenu.triggered.connect(self._on_click(entry[1]))
help_menu = {"title": "Keyboard Shortcuts", "text": """
<body style='margin-right:46px;'><b>
F11 Toggle Full Screen
<br>
F10 Toggle Corner Window
<br>
CTRL + Zoom In
<br>
CTRL - Zoom Out
</body>
"""},\
{"title": "About JAK", "text": """
<body style='margin-right:46px;'>
<small>
This online application is copyright and ownership of their respective authors.
<br><br>
This wrapper offers the ability to run web applications, as a self contained native desktop application.
Enjoy.
</small>
<br>
<center>
<b><small>
Powered by:
</b></small>
<a href='https://github.com/codesardine/Jade-Application-Kit'>Jade Application Kit</a><center>
<small>
Native Hybrid Apps on Linux.
<br>
<b>
Using QT WebEngine
<b>
</small>
<br>
<small>
<br>
This application comes with no warranty. License: <b>GPL</b>
<br>
Author:<b>Vitor Lopes<b>
</small>
</center>
</body>
"""}
help = self.addMenu("Help")
for entry in help_menu:
submenu = QAction(entry["title"], self)
submenu.triggered.connect(self._on_click(entry["text"], entry["title"]))
help.addAction(submenu)
def _on_click(self, url: str, title=""):
if url.startswith("https"):
view = Instance.retrieve("view")
return lambda: view.setUrl(QUrl(url))
elif url.endswith("()"):
from JAK import IPC
return lambda: IPC.Communication.send(url)
else:
msg = url
return lambda: Dialog.information(self, title, msg)
class Dialog:
@staticmethod
def question(parent, title, msg, on_confirm=""):
reply = QMessageBox.question(parent, title, msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
on_confirm()
@staticmethod
def information(parent, title, msg):
QMessageBox.information(parent, title, msg)
class FileChooserDialog(QWidget):
def __init__(self, parent=None, file_type="", title="Choose a File"):
super().__init__(parent)
self.file_type = file_type
self.title = title
self.show()
def choose_file(self):
dialog = QFileDialog()
options = dialog.Options()
file_name = dialog.getOpenFileName(
self, self.title, os.environ['HOME'],
f"{self.file_type.upper()} Files ({self.file_type})",
options=options)
if file_name[0]:
return file_name[0]
self.hide()
self.destroy()