qcanvas 1.2.1__py3-none-any.whl → 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of qcanvas might be problematic. Click here for more details.
- qcanvas/__init__.py +54 -0
- qcanvas/app.py +93 -0
- qcanvas/backend_connectors/frontend_resource_manager.py +13 -5
- qcanvas/backend_connectors/qcanvas_task_master.py +2 -2
- qcanvas/icons/__init__.py +5 -5
- qcanvas/icons/_icon_type.py +1 -1
- qcanvas/icons/icons.qrc +47 -43
- qcanvas/icons/rc_icons.py +1298 -1197
- qcanvas/settings/__init__.py +6 -0
- qcanvas/{util/settings → settings}/_client_settings.py +4 -4
- qcanvas/settings/_course_settings.py +54 -0
- qcanvas/{util/settings → settings}/_mapped_setting.py +2 -5
- qcanvas/{util/settings → settings}/_ui_settings.py +5 -5
- qcanvas/theme.py +101 -0
- qcanvas/ui/course_viewer/content_tree.py +9 -12
- qcanvas/ui/course_viewer/course_tree/_course_icon_generator.py +3 -3
- qcanvas/ui/course_viewer/course_tree/course_tree.py +9 -8
- qcanvas/ui/course_viewer/course_viewer.py +35 -43
- qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tab.py +107 -29
- qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tree.py +4 -4
- qcanvas/ui/course_viewer/tabs/constants.py +1 -0
- qcanvas/ui/course_viewer/tabs/content_tab.py +33 -39
- qcanvas/ui/course_viewer/tabs/file_tab/file_tab.py +4 -4
- qcanvas/ui/course_viewer/tabs/file_tab/file_tree.py +7 -10
- qcanvas/ui/course_viewer/tabs/file_tab/pages_file_tree.py +6 -7
- qcanvas/ui/course_viewer/tabs/mail_tab/mail_tab.py +50 -27
- qcanvas/ui/course_viewer/tabs/mail_tab/mail_tree.py +7 -8
- qcanvas/ui/course_viewer/tabs/page_tab/page_tab.py +3 -3
- qcanvas/ui/course_viewer/tabs/page_tab/page_tree.py +5 -5
- qcanvas/ui/course_viewer/tabs/resource_rich_browser.py +15 -21
- qcanvas/ui/course_viewer/tree_widget_data_item.py +1 -1
- qcanvas/ui/memory_tree/_tree_memory.py +45 -42
- qcanvas/ui/memory_tree/memory_tree_widget.py +22 -18
- qcanvas/ui/memory_tree/memory_tree_widget_item.py +3 -3
- qcanvas/ui/qcanvas_window/__init__.py +1 -0
- qcanvas/ui/{main_ui → qcanvas_window}/course_viewer_container.py +10 -10
- qcanvas/ui/{main_ui → qcanvas_window}/options/auto_download_resources_option.py +5 -5
- qcanvas/ui/{main_ui → qcanvas_window}/options/quick_sync_option.py +7 -6
- qcanvas/ui/{main_ui → qcanvas_window}/options/sync_on_start_option.py +7 -6
- qcanvas/ui/{main_ui → qcanvas_window}/options/theme_selection_menu.py +10 -10
- qcanvas/ui/{main_ui → qcanvas_window}/qcanvas_window.py +42 -36
- qcanvas/ui/{main_ui → qcanvas_window}/status_bar_progress_display.py +5 -6
- qcanvas/ui/qml_components/AttachmentsList.ui.qml +15 -0
- qcanvas/ui/qml_components/AttachmentsListDelegate.qml +77 -0
- qcanvas/ui/qml_components/AttachmentsListModel.qml +19 -0
- qcanvas/ui/qml_components/AttachmentsPane.qml +12 -0
- qcanvas/ui/qml_components/CommentsList.ui.qml +15 -0
- qcanvas/ui/qml_components/CommentsListDelegate.ui.qml +118 -0
- qcanvas/ui/qml_components/CommentsListModel.qml +56 -0
- qcanvas/ui/qml_components/CommentsPane.qml +12 -0
- qcanvas/ui/qml_components/DarkTheme.qml +12 -0
- qcanvas/ui/qml_components/DecoratedText.ui.qml +44 -0
- qcanvas/ui/qml_components/LightTheme.qml +11 -0
- qcanvas/ui/qml_components/Spacer.ui.qml +7 -0
- qcanvas/ui/qml_components/ThemedRectangle.qml +37 -0
- qcanvas/ui/qml_components/__init__.py +3 -0
- qcanvas/ui/qml_components/attachments_pane.py +72 -0
- qcanvas/ui/qml_components/comments_pane.py +85 -0
- qcanvas/ui/qml_components/qml_bridge_types.py +95 -0
- qcanvas/ui/qml_components/qml_pane.py +22 -0
- qcanvas/ui/setup/setup_checker.py +1 -1
- qcanvas/ui/setup/setup_dialog.py +27 -10
- qcanvas/util/auto_downloader.py +9 -7
- qcanvas/util/basic_fonts.py +2 -2
- qcanvas/util/context_dict.py +12 -0
- qcanvas/util/file_icons.py +11 -19
- qcanvas/util/layouts.py +5 -7
- qcanvas/util/paths.py +17 -6
- qcanvas/util/qurl_util.py +1 -1
- qcanvas/util/ui_tools.py +118 -8
- qcanvas/util/url_checker.py +1 -1
- {qcanvas-1.2.1.dist-info → qcanvas-2.0.0.dist-info}/METADATA +13 -11
- qcanvas-2.0.0.dist-info/RECORD +91 -0
- {qcanvas-1.2.1.dist-info → qcanvas-2.0.0.dist-info}/WHEEL +1 -1
- qcanvas-2.0.0.dist-info/entry_points.txt +3 -0
- qcanvas/app_start/__init__.py +0 -59
- qcanvas/icons/_update_icons.py +0 -89
- qcanvas/icons/dark/actions/exit.svg +0 -3
- qcanvas/icons/dark/actions/mark_all_read.svg +0 -3
- qcanvas/icons/dark/actions/open_downloads.svg +0 -3
- qcanvas/icons/dark/actions/quick_login.svg +0 -3
- qcanvas/icons/dark/actions/sync.svg +0 -3
- qcanvas/icons/dark/branding/logo_transparent.svg +0 -303
- qcanvas/icons/dark/options/auto_download.svg +0 -3
- qcanvas/icons/dark/options/theme.svg +0 -3
- qcanvas/icons/dark/tabs/assignments.svg +0 -3
- qcanvas/icons/dark/tabs/mail.svg +0 -3
- qcanvas/icons/dark/tabs/pages.svg +0 -3
- qcanvas/icons/dark/tree_items/assignment.svg +0 -3
- qcanvas/icons/dark/tree_items/mail.svg +0 -3
- qcanvas/icons/dark/tree_items/module.svg +0 -3
- qcanvas/icons/dark/tree_items/page.svg +0 -3
- qcanvas/icons/light/actions/exit.svg +0 -3
- qcanvas/icons/light/actions/mark_all_read.svg +0 -3
- qcanvas/icons/light/actions/open_downloads.svg +0 -3
- qcanvas/icons/light/actions/quick_login.svg +0 -3
- qcanvas/icons/light/actions/sync.svg +0 -3
- qcanvas/icons/light/branding/logo_transparent.svg +0 -304
- qcanvas/icons/light/options/auto_download.svg +0 -3
- qcanvas/icons/light/options/ignore_old.svg +0 -3
- qcanvas/icons/light/options/include_videos.svg +0 -3
- qcanvas/icons/light/options/theme.svg +0 -3
- qcanvas/icons/light/tabs/assignments.svg +0 -3
- qcanvas/icons/light/tabs/mail.svg +0 -3
- qcanvas/icons/light/tabs/pages.svg +0 -3
- qcanvas/icons/light/tree_items/assignment.svg +0 -3
- qcanvas/icons/light/tree_items/mail.svg +0 -3
- qcanvas/icons/light/tree_items/module.svg +0 -3
- qcanvas/icons/light/tree_items/page.svg +0 -3
- qcanvas/icons/universal/branding/main_icon.svg +0 -325
- qcanvas/icons/universal/downloads/download_failed.svg +0 -23
- qcanvas/icons/universal/downloads/downloaded.svg +0 -23
- qcanvas/icons/universal/downloads/not_downloaded.svg +0 -23
- qcanvas/icons/universal/downloads/unknown.svg +0 -6
- qcanvas/icons/universal/tabs/assignments_new_content.svg +0 -3
- qcanvas/icons/universal/tabs/mail_new_content.svg +0 -3
- qcanvas/icons/universal/tabs/pages_new_content.svg +0 -3
- qcanvas/icons/universal/tree_items/semester.svg +0 -108
- qcanvas/run.py +0 -54
- qcanvas/ui/course_viewer/tabs/util.py +0 -11
- qcanvas/ui/main_ui/__init__.py +0 -0
- qcanvas/util/settings/__init__.py +0 -9
- qcanvas/util/themes/__init__.py +0 -2
- qcanvas/util/themes/_colour_scheme_helper.py +0 -38
- qcanvas/util/themes/_selected_theme.py +0 -10
- qcanvas/util/themes/_theme_changed_event.py +0 -17
- qcanvas/util/themes/_theme_changer.py +0 -86
- qcanvas-1.2.1.dist-info/RECORD +0 -118
- qcanvas-1.2.1.dist-info/entry_points.txt +0 -3
- /qcanvas/ui/{main_ui → qcanvas_window}/options/__init__.py +0 -0
qcanvas/util/auto_downloader.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
from
|
|
4
|
+
from PySide6.QtCore import Qt
|
|
5
|
+
from libqcanvas import db
|
|
6
|
+
from libqcanvas.net.resources.download.resource_manager import ResourceManager
|
|
7
|
+
from libqcanvas.net.sync.sync_receipt import SyncReceipt
|
|
8
|
+
from PySide6.QtWidgets import QMessageBox, QWidget
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
import qcanvas.settings as settings
|
|
10
11
|
|
|
11
12
|
_logger = logging.getLogger(__name__)
|
|
12
13
|
|
|
@@ -20,7 +21,7 @@ async def download_new_resources(
|
|
|
20
21
|
) -> None:
|
|
21
22
|
resources_to_download = []
|
|
22
23
|
|
|
23
|
-
for file_id in receipt.
|
|
24
|
+
for file_id in receipt.updates[db.Resource]:
|
|
24
25
|
resource = all_resources[file_id]
|
|
25
26
|
|
|
26
27
|
if _should_auto_download_resource(resource, resource_manager=downloader):
|
|
@@ -36,7 +37,8 @@ async def download_new_resources(
|
|
|
36
37
|
msg.accepted.connect(
|
|
37
38
|
lambda: asyncio.get_running_loop().create_task(
|
|
38
39
|
downloader.batch_download(resources_to_download),
|
|
39
|
-
)
|
|
40
|
+
),
|
|
41
|
+
Qt.ConnectionType.SingleShotConnection,
|
|
40
42
|
)
|
|
41
43
|
else:
|
|
42
44
|
await downloader.batch_download(resources_to_download)
|
qcanvas/util/basic_fonts.py
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from PySide6.QtQml import QQmlContext
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ContextDict:
|
|
5
|
+
def __init__(self, context: QQmlContext):
|
|
6
|
+
self._context = context
|
|
7
|
+
|
|
8
|
+
def __getitem__(self, item):
|
|
9
|
+
return self._context.contextProperty(item)
|
|
10
|
+
|
|
11
|
+
def __setitem__(self, key, value):
|
|
12
|
+
self._context.setContextProperty(key, value)
|
qcanvas/util/file_icons.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os.path
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
from
|
|
6
|
-
from
|
|
4
|
+
import cachetools
|
|
5
|
+
from PySide6.QtCore import QFileInfo, QMimeDatabase
|
|
6
|
+
from PySide6.QtGui import QIcon
|
|
7
|
+
from PySide6.QtWidgets import QApplication, QFileIconProvider, QStyle
|
|
7
8
|
|
|
8
9
|
import qcanvas.util.runtime as runtime
|
|
9
10
|
|
|
@@ -18,13 +19,9 @@ if runtime.is_running_on_windows:
|
|
|
18
19
|
|
|
19
20
|
else:
|
|
20
21
|
_mime_database = QMimeDatabase()
|
|
21
|
-
# This must be initialised lazily because the QApplication might not be initialised at this time
|
|
22
|
-
_default_icon: QIcon | None = None
|
|
23
22
|
_icon_for_suffix: dict[str, QIcon] = {}
|
|
24
23
|
|
|
25
24
|
def icon_for_filename(file_name: str) -> QIcon:
|
|
26
|
-
global _default_icon
|
|
27
|
-
|
|
28
25
|
file_suffix = os.path.splitext(file_name)[1]
|
|
29
26
|
|
|
30
27
|
# Check if we already know what icon this file type has
|
|
@@ -39,16 +36,11 @@ else:
|
|
|
39
36
|
_icon_for_suffix[file_suffix] = icon
|
|
40
37
|
return icon
|
|
41
38
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return _default_icon
|
|
47
|
-
|
|
48
|
-
def _lazy_init_default_icon() -> None:
|
|
49
|
-
global _default_icon
|
|
39
|
+
# No icon for this type of file was found, use default icon
|
|
40
|
+
icon = _default_icon()
|
|
41
|
+
_icon_for_suffix[file_suffix] = icon
|
|
42
|
+
return icon
|
|
50
43
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
)
|
|
44
|
+
@cachetools.cached(cachetools.LRUCache(maxsize=1))
|
|
45
|
+
def _default_icon() -> QIcon:
|
|
46
|
+
return QApplication.style().standardIcon(QStyle.StandardPixmap.SP_FileIcon)
|
qcanvas/util/layouts.py
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Iterable, NamedTuple
|
|
3
3
|
|
|
4
|
-
from
|
|
5
|
-
from
|
|
4
|
+
from PySide6.QtCore import Qt
|
|
5
|
+
from PySide6.QtWidgets import QGridLayout, QLayout, QWidget
|
|
6
6
|
|
|
7
7
|
_logger = logging.getLogger(__name__)
|
|
8
8
|
|
|
9
|
-
T = TypeVar("T")
|
|
10
|
-
|
|
11
9
|
|
|
12
10
|
class GridItem(NamedTuple):
|
|
13
11
|
widget: QWidget
|
|
@@ -16,13 +14,13 @@ class GridItem(NamedTuple):
|
|
|
16
14
|
alignment: Qt.AlignmentFlag = Qt.AlignmentFlag.AlignLeft
|
|
17
15
|
|
|
18
16
|
|
|
19
|
-
def layout_widget(layout_type:
|
|
17
|
+
def layout_widget[T](layout_type: type[T], *items: QWidget, **kwargs) -> QWidget:
|
|
20
18
|
widget = QWidget()
|
|
21
19
|
widget.setLayout(layout(layout_type, *items, **kwargs))
|
|
22
20
|
return widget
|
|
23
21
|
|
|
24
22
|
|
|
25
|
-
def layout(layout_type:
|
|
23
|
+
def layout[T](layout_type: type[T], *items: QWidget | QLayout, **kwargs) -> T:
|
|
26
24
|
result_layout: QLayout = layout_type(**kwargs)
|
|
27
25
|
|
|
28
26
|
for item in items:
|
qcanvas/util/paths.py
CHANGED
|
@@ -4,21 +4,30 @@ from pathlib import Path
|
|
|
4
4
|
|
|
5
5
|
import cachetools
|
|
6
6
|
import platformdirs
|
|
7
|
-
from
|
|
7
|
+
from PySide6.QtCore import QSettings
|
|
8
8
|
|
|
9
|
-
from qcanvas.util.runtime import
|
|
9
|
+
from qcanvas.util.runtime import (
|
|
10
|
+
is_running_as_compiled,
|
|
11
|
+
is_running_as_flatpak,
|
|
12
|
+
is_running_portable,
|
|
13
|
+
)
|
|
10
14
|
|
|
11
15
|
_logger = logging.getLogger(__name__)
|
|
12
16
|
|
|
13
17
|
|
|
14
|
-
def ui_storage() -> Path:
|
|
15
|
-
return root() / ".UI"
|
|
16
|
-
|
|
17
|
-
|
|
18
18
|
def data_storage() -> Path:
|
|
19
19
|
return root()
|
|
20
20
|
|
|
21
21
|
|
|
22
|
+
def config_storage() -> Path:
|
|
23
|
+
if is_running_portable:
|
|
24
|
+
return root()
|
|
25
|
+
else:
|
|
26
|
+
path = platformdirs.user_config_path("QCanvasTeam", "QCanvas")
|
|
27
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
28
|
+
return path
|
|
29
|
+
|
|
30
|
+
|
|
22
31
|
def client_settings() -> QSettings:
|
|
23
32
|
if is_running_portable:
|
|
24
33
|
return QSettings("QCanvas.ini", QSettings.Format.IniFormat)
|
|
@@ -35,6 +44,8 @@ def root() -> Path:
|
|
|
35
44
|
root_path = Path(os.environ["XDG_DATA_HOME"])
|
|
36
45
|
elif not is_running_portable and is_running_as_compiled:
|
|
37
46
|
root_path = platformdirs.user_data_path("QCanvasReborn", "QCanvasTeam")
|
|
47
|
+
elif not is_running_portable:
|
|
48
|
+
_logger.warning("Don't know how we're being run? Are you running from source?")
|
|
38
49
|
|
|
39
50
|
print("Root path", root_path.absolute())
|
|
40
51
|
_logger.debug("Root path %s", root_path.absolute())
|
qcanvas/util/qurl_util.py
CHANGED
qcanvas/util/ui_tools.py
CHANGED
|
@@ -1,14 +1,124 @@
|
|
|
1
|
-
import
|
|
2
|
-
from typing import Any
|
|
1
|
+
from typing import Any, Sequence
|
|
3
2
|
|
|
4
|
-
from
|
|
5
|
-
from
|
|
3
|
+
from PySide6.QtCore import QSize
|
|
4
|
+
from PySide6.QtGui import QAction, QIcon, QKeySequence, QPixmap, QFont
|
|
5
|
+
from PySide6.QtWidgets import (
|
|
6
|
+
QMenu,
|
|
7
|
+
QSizePolicy,
|
|
8
|
+
QLabel,
|
|
9
|
+
QWidget,
|
|
10
|
+
QFormLayout,
|
|
11
|
+
QDockWidget,
|
|
12
|
+
QLayout,
|
|
13
|
+
QHBoxLayout,
|
|
14
|
+
QVBoxLayout,
|
|
15
|
+
)
|
|
6
16
|
|
|
7
|
-
_logger = logging.getLogger(__name__)
|
|
8
17
|
|
|
18
|
+
def font(*, point_size: float | int | None = None, bold: bool | None = None) -> QFont:
|
|
19
|
+
_font = QFont()
|
|
9
20
|
|
|
10
|
-
|
|
11
|
-
|
|
21
|
+
if point_size is not None:
|
|
22
|
+
if isinstance(point_size, int):
|
|
23
|
+
_font.setPointSize(point_size)
|
|
24
|
+
elif isinstance(point_size, float):
|
|
25
|
+
_font.setPointSizeF(point_size)
|
|
26
|
+
else:
|
|
27
|
+
raise TypeError("point_size")
|
|
28
|
+
|
|
29
|
+
if bold is not None:
|
|
30
|
+
_font.setBold(bold)
|
|
31
|
+
|
|
32
|
+
return _font
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
_bold = font(bold=True)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def label(text: str, *, font: QFont = None, allow_truncation: bool = False) -> QLabel:
|
|
39
|
+
_label = QLabel(text)
|
|
40
|
+
|
|
41
|
+
if font is not None:
|
|
42
|
+
_label.setFont(font)
|
|
43
|
+
|
|
44
|
+
if allow_truncation:
|
|
45
|
+
_label.setSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Fixed)
|
|
46
|
+
|
|
47
|
+
return _label
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def bold_label(text: str, *, allow_truncation: bool = False) -> QLabel:
|
|
51
|
+
return label(text, allow_truncation=allow_truncation, font=_bold)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def form_layout(
|
|
55
|
+
rows: dict[str, QWidget], label_font: QFont | None = _bold, label_suffix: str = ":"
|
|
56
|
+
) -> QFormLayout:
|
|
57
|
+
layout = QFormLayout()
|
|
58
|
+
|
|
59
|
+
for name, widget in rows.items():
|
|
60
|
+
if label_font:
|
|
61
|
+
layout.addRow(label(name + label_suffix, font=label_font), widget)
|
|
62
|
+
else:
|
|
63
|
+
layout.addRow(name + label_suffix, widget)
|
|
64
|
+
|
|
65
|
+
return layout
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def size(width: int, height: int):
|
|
69
|
+
return QSize(width, height)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def dock_widget(
|
|
73
|
+
*,
|
|
74
|
+
widget: QWidget,
|
|
75
|
+
title: str | None = None,
|
|
76
|
+
hide: bool = False,
|
|
77
|
+
name: str | None = None,
|
|
78
|
+
min_size: QSize | None = None,
|
|
79
|
+
features: QDockWidget.DockWidgetFeature | None = None,
|
|
80
|
+
parent: QWidget | None = None,
|
|
81
|
+
) -> QDockWidget:
|
|
82
|
+
dock = QDockWidget(title, parent)
|
|
83
|
+
dock.setWidget(widget)
|
|
84
|
+
|
|
85
|
+
if name is not None:
|
|
86
|
+
dock.setObjectName(name)
|
|
87
|
+
|
|
88
|
+
if min_size is not None:
|
|
89
|
+
dock.setMinimumSize(min_size)
|
|
90
|
+
|
|
91
|
+
if features is not None:
|
|
92
|
+
dock.setFeatures(features)
|
|
93
|
+
|
|
94
|
+
if hide:
|
|
95
|
+
dock.hide()
|
|
96
|
+
|
|
97
|
+
return dock
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def widget(layout: QLayout) -> QWidget:
|
|
101
|
+
widget = QWidget()
|
|
102
|
+
widget.setLayout(layout)
|
|
103
|
+
return widget
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def hbox(*items: QWidget | QLayout) -> QHBoxLayout:
|
|
107
|
+
_add_layout_items(layout := QHBoxLayout(), items)
|
|
108
|
+
return layout
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def vbox(*items: QWidget | QLayout) -> QVBoxLayout:
|
|
112
|
+
_add_layout_items(layout := QVBoxLayout(), items)
|
|
113
|
+
return layout
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _add_layout_items(layout: QLayout, items: Sequence[QWidget | QLayout]):
|
|
117
|
+
for item in items:
|
|
118
|
+
if isinstance(item, QLayout):
|
|
119
|
+
layout.addItem(item)
|
|
120
|
+
else:
|
|
121
|
+
layout.addWidget(item)
|
|
12
122
|
|
|
13
123
|
|
|
14
124
|
def create_qaction(
|
|
@@ -19,7 +129,7 @@ def create_qaction(
|
|
|
19
129
|
triggered: Any = None,
|
|
20
130
|
checkable: bool | None = None,
|
|
21
131
|
checked: bool | None = None,
|
|
22
|
-
icon: QIcon | QPixmap | None = None
|
|
132
|
+
icon: QIcon | QPixmap | None = None,
|
|
23
133
|
) -> QAction:
|
|
24
134
|
action = QAction(name)
|
|
25
135
|
|
qcanvas/util/url_checker.py
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: qcanvas
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: QCanvas is a desktop client for Canvas LMS.
|
|
5
5
|
Author: QCanvas
|
|
6
6
|
Author-email: QCanvas@noreply.codeberg.org
|
|
7
|
-
Requires-Python:
|
|
7
|
+
Requires-Python: >=3.12,<3.13
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Requires-Dist: aiofile (>=3.9.0,<4.0.0)
|
|
10
11
|
Requires-Dist: aiosqlite (>=0.20.0,<0.21.0)
|
|
11
12
|
Requires-Dist: asynctaskpool (>=0.2.1,<0.3.0)
|
|
12
|
-
Requires-Dist:
|
|
13
|
+
Requires-Dist: cachetools (>=5.5.0,<6.0.0)
|
|
14
|
+
Requires-Dist: libqcanvas (>=0.5.1,<0.6.0)
|
|
13
15
|
Requires-Dist: platformdirs (>=4.2.2,<5.0.0)
|
|
14
16
|
Requires-Dist: pyqtdarktheme-fork (>=2.3.2,<3.0.0)
|
|
15
17
|
Requires-Dist: qasync (>=0.27.1,<0.28.0)
|
|
16
|
-
Requires-Dist: qcanvas-api-clients (>=0.3.0,<0.4.0)
|
|
17
|
-
Requires-Dist: qcanvas-backend (>=0.2.7,<0.3.0)
|
|
18
|
-
Requires-Dist: qtpy (>=2.4.1,<3.0.0)
|
|
19
18
|
Requires-Dist: sqlalchemy (>=2.0.31,<3.0.0)
|
|
20
|
-
Requires-Dist: validators (>=0.
|
|
19
|
+
Requires-Dist: validators (>=0.34.0,<0.35.0)
|
|
21
20
|
Description-Content-Type: text/markdown
|
|
22
21
|
|
|
23
22
|
# QCanvas
|
|
@@ -43,7 +42,7 @@ based distros.
|
|
|
43
42
|
|
|
44
43
|
## Prerequisites
|
|
45
44
|
|
|
46
|
-
- Python 3.
|
|
45
|
+
- Python 3.11+ (use [pyenv](https://github.com/pyenv/pyenv) if your distro does not have that version)
|
|
47
46
|
- [Pipx](https://pipx.pypa.io/stable/) (optional)
|
|
48
47
|
- Poetry (recommended to install using `pipx install poetry`)
|
|
49
48
|
- [Appimagetool](https://github.com/AppImage/appimagetool) (Only for building the appimage)
|
|
@@ -57,15 +56,18 @@ cd QCanvasApp
|
|
|
57
56
|
# Enter shell and run it
|
|
58
57
|
poetry shell
|
|
59
58
|
poetry install
|
|
60
|
-
python qcanvas
|
|
59
|
+
python -m qcanvas
|
|
61
60
|
|
|
62
61
|
# Alternatively you can run it like this:
|
|
63
62
|
poetry install
|
|
64
|
-
poetry run python qcanvas
|
|
63
|
+
poetry run python -m qcanvas
|
|
65
64
|
```
|
|
66
65
|
|
|
67
66
|
## Build custom AppImage
|
|
68
67
|
|
|
68
|
+
> [!INFO]
|
|
69
|
+
> This is not recommended as the appimage produced by this process isn't a proper appimage.
|
|
70
|
+
|
|
69
71
|
```bash
|
|
70
72
|
bash build_appimage.sh
|
|
71
73
|
```
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
qcanvas/__init__.py,sha256=FSRKOgINpdkHq1lU0lzAKl6v6KmMYOyGcihFpf2HIQs,1719
|
|
2
|
+
qcanvas/app.py,sha256=NNxjdzFtRaeGk0cSOHKepwK7ONvHwmY_RcW0IVVzoIs,2747
|
|
3
|
+
qcanvas/backend_connectors/__init__.py,sha256=Wj8cmxQng3SSlmlXJyzHaPmvxbkauwsxINckPb7WuHc,108
|
|
4
|
+
qcanvas/backend_connectors/frontend_resource_manager.py,sha256=uzi8z2bNBdQoVkvtwxWo4qX5r0s13qmH5QL2t0vD0d8,1613
|
|
5
|
+
qcanvas/backend_connectors/qcanvas_task_master.py,sha256=G46WgM4LA9VGWUDe3cBfRqHEYrOqcM70UJ5ipwc8hm0,740
|
|
6
|
+
qcanvas/icons/__init__.py,sha256=RHBT64IkUdQQtSRRxsMU1uiYRPvUoTHJV01x9WXHepA,1965
|
|
7
|
+
qcanvas/icons/_icon_type.py,sha256=_Xq0qwz_4OsAOhT6_4lEWTFMsPSqKVRkmQjfXbJAeAE,904
|
|
8
|
+
qcanvas/icons/icons.qrc,sha256=ec-_Hiy2GOA0NOQCeyRpIhexTZk0_SSDxZlWSvSUgno,2084
|
|
9
|
+
qcanvas/icons/rc_icons.py,sha256=SZBFaQaLym2jkJ90csM-2W8TKWgBLMyRxnZUO0yAw_0,74285
|
|
10
|
+
qcanvas/settings/__init__.py,sha256=GPOgh9fzK0zGiJhIy7fWfXJZVE86i6DE-ZjQSqFunco,176
|
|
11
|
+
qcanvas/settings/_client_settings.py,sha256=6Oy5eXlttlwC11YSqbqLcgyVa5Nk3jBdB4Ea-gFC-yw,1397
|
|
12
|
+
qcanvas/settings/_course_settings.py,sha256=mNNPNt88f5q1m_YtoqaHDUqoAiRnVZj4wUGd0xDlcjY,1547
|
|
13
|
+
qcanvas/settings/_mapped_setting.py,sha256=a9wq60chtn9X8RLpQrf6JR7XsDxJlJfWrq0hfHHJvyU,1928
|
|
14
|
+
qcanvas/settings/_ui_settings.py,sha256=gyC_ZwPdu4JzZgA4I6TelJmm6pXginBigp58u-fBd3w,753
|
|
15
|
+
qcanvas/theme.py,sha256=7GVSpc1VCHxQiM7eamPNQJJKikVE8rejAsUFYOvsuaQ,3077
|
|
16
|
+
qcanvas/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
qcanvas/ui/course_viewer/__init__.py,sha256=XkoFnh4ULw3_i-GDsOlueEWido0PkoDcN9_EX6-nkXY,76
|
|
18
|
+
qcanvas/ui/course_viewer/content_tree.py,sha256=ewgi4oNN3uCURjykpLLRb2efzBxfFws14UAQ3H6z-64,4602
|
|
19
|
+
qcanvas/ui/course_viewer/course_tree/__init__.py,sha256=N2XorJ4COFHzRYx53noANb4_qJYf6N8_YCjPdQuDCHs,36
|
|
20
|
+
qcanvas/ui/course_viewer/course_tree/_course_icon_generator.py,sha256=facgU1YPLpPy5C6EJG5KURuKTn7LOTu9ZmPEj-UQLFI,3080
|
|
21
|
+
qcanvas/ui/course_viewer/course_tree/course_tree.py,sha256=KaPVdvS2tPdMZFhggWCvg9DVSQugHS_EpGa12vgGNyw,3224
|
|
22
|
+
qcanvas/ui/course_viewer/course_viewer.py,sha256=AGZ6eQlRLb1i2ex-gbe2ygT3_sHYD7bvXy3tYQ2Jugc,4974
|
|
23
|
+
qcanvas/ui/course_viewer/tabs/__init__.py,sha256=SlfWUzk6_E5uM9GIV-y9BVeKMwqn3pRx_xWhMyb1dfI,54
|
|
24
|
+
qcanvas/ui/course_viewer/tabs/assignment_tab/__init__.py,sha256=w936dW7za10Fh6rN0zVA-7Kyiup3kd6C-mPAFHtxmy0,42
|
|
25
|
+
qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tab.py,sha256=HAy6SsPTC-FpaaTWELS7lc5rgkB3Wm0m3DIHb3cvaaI,4850
|
|
26
|
+
qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tree.py,sha256=Lwj3Sq_W_XFV240VpLK6W3kIUQ00NH9qB88mAKsYHNs,2908
|
|
27
|
+
qcanvas/ui/course_viewer/tabs/constants.py,sha256=rUVEGSREV9vTFs4o3AD2OjaSFA-GPsmelxYWz0J8OP4,48
|
|
28
|
+
qcanvas/ui/course_viewer/tabs/content_tab.py,sha256=l2h1Vl7t0GAFYXzEjihMzpBv596sOu8BJKiMz1lcFAE,3274
|
|
29
|
+
qcanvas/ui/course_viewer/tabs/file_tab/__init__.py,sha256=mMebnrNw_V-lQ-eBXS_kFinL-ZdUAXa459NmuyuCu6s,30
|
|
30
|
+
qcanvas/ui/course_viewer/tabs/file_tab/file_tab.py,sha256=SeKGKNRLmSmL5Ij96YSRx6Skl-1wC14uDfIPJy_xmzw,1398
|
|
31
|
+
qcanvas/ui/course_viewer/tabs/file_tab/file_tree.py,sha256=ely6qZTs6CFsKv9ZFDCAe_8unosJ6nt9AQFLkcuknvE,3357
|
|
32
|
+
qcanvas/ui/course_viewer/tabs/file_tab/pages_file_tree.py,sha256=C1QtoY9GA2Q_lbUearVrdZbHCAefV4ZpsIPHGBAUxPI,1875
|
|
33
|
+
qcanvas/ui/course_viewer/tabs/mail_tab/__init__.py,sha256=68iRUUWEP7mudbaxa4ZBKMra4rvs2oZKaZkBWwmUrsI,30
|
|
34
|
+
qcanvas/ui/course_viewer/tabs/mail_tab/mail_tab.py,sha256=FGfRaEAcuLfcPo92_D7ZcyeIjePMbU_BSlpAtyT0qLo,2686
|
|
35
|
+
qcanvas/ui/course_viewer/tabs/mail_tab/mail_tree.py,sha256=w4dkC4V_fKsMkVB68vbfvMRI1HBxbuKzxExclAn-AaQ,1762
|
|
36
|
+
qcanvas/ui/course_viewer/tabs/page_tab/__init__.py,sha256=lcafxlSEVZ0wqZySxT6hTrvExX-GU2AfcZQbp6W8haU,30
|
|
37
|
+
qcanvas/ui/course_viewer/tabs/page_tab/page_tab.py,sha256=-u6RaH7kO1cCrvcXNF0hcLrEL6nomy6IUXfKEGhANgg,743
|
|
38
|
+
qcanvas/ui/course_viewer/tabs/page_tab/page_tree.py,sha256=mxQzhjiiO7onQALhKbcyQQtsKEdBGAspQreXljRu9i4,2147
|
|
39
|
+
qcanvas/ui/course_viewer/tabs/resource_rich_browser.py,sha256=BlUHqoNKu5vzmLIYjUJZX6APxeNA2bia4xRZ3B0gaqc,6479
|
|
40
|
+
qcanvas/ui/course_viewer/tree_widget_data_item.py,sha256=z3CnXNFivtDtKemkH41E0a_Dc-l_tKJ6AEqNqM23eao,569
|
|
41
|
+
qcanvas/ui/memory_tree/__init__.py,sha256=-XLitM6teC0zmwPrGf-Q-A53-zgmIPASExdOtaLIvPU,107
|
|
42
|
+
qcanvas/ui/memory_tree/_tree_memory.py,sha256=kPsAw0sL5AFPIhWuhfKSS56043t9pQFi2YpBdYkbfm0,2231
|
|
43
|
+
qcanvas/ui/memory_tree/memory_tree_widget.py,sha256=NT8T9EMql7xxVRCQFkfb1p0h3gL7oQq9As2UGy_481k,4553
|
|
44
|
+
qcanvas/ui/memory_tree/memory_tree_widget_item.py,sha256=76a7IEZGXwYhqx7WMbq-tA_GvinvQW7hdueZNWAvFxg,435
|
|
45
|
+
qcanvas/ui/qcanvas_window/__init__.py,sha256=GeMsShFH9OGYLDDgB0KmKHlJr32NeewxurM-QzgabSQ,42
|
|
46
|
+
qcanvas/ui/qcanvas_window/course_viewer_container.py,sha256=oEPdqnGU752JTY0p4HfSlFyNDw-12AW4JzgxZ1A31J0,3502
|
|
47
|
+
qcanvas/ui/qcanvas_window/options/__init__.py,sha256=SlfWUzk6_E5uM9GIV-y9BVeKMwqn3pRx_xWhMyb1dfI,54
|
|
48
|
+
qcanvas/ui/qcanvas_window/options/auto_download_resources_option.py,sha256=oeVdUsFUSrCRKKjb6eyjsJecaMSMnEKR66L9FTlm_Eo,1379
|
|
49
|
+
qcanvas/ui/qcanvas_window/options/quick_sync_option.py,sha256=16zEFL__JRi-wE7Q99_Bqi-OHEBhRgf5QlnVUOUX3Eg,833
|
|
50
|
+
qcanvas/ui/qcanvas_window/options/sync_on_start_option.py,sha256=gL_FIulULN1uGBJJWgUszyjayQDw5WfppjoErbM3850,773
|
|
51
|
+
qcanvas/ui/qcanvas_window/options/theme_selection_menu.py,sha256=VMx79H45R7lcpMFpaN8eohbCxkQkq43MdH8W0nt2aTQ,1434
|
|
52
|
+
qcanvas/ui/qcanvas_window/qcanvas_window.py,sha256=VDgoBpldNAu_7Rj4BqT7KQOgcBN1Koq6c0s0uduumc8,8945
|
|
53
|
+
qcanvas/ui/qcanvas_window/status_bar_progress_display.py,sha256=v8cL7EzhKIO6YDo-IJGC2TvjnaHvHb9F2VyJtW0W4U8,5047
|
|
54
|
+
qcanvas/ui/qml_components/AttachmentsList.ui.qml,sha256=kEgdn1s490hfvMtDtbba54_-_vF-3GUIEVpB8D12ET0,483
|
|
55
|
+
qcanvas/ui/qml_components/AttachmentsListDelegate.qml,sha256=Frcd-vMd6lXBICF8SpPdpGJgxrk4vasvK29uTxXKAcs,2115
|
|
56
|
+
qcanvas/ui/qml_components/AttachmentsListModel.qml,sha256=y4pQoJLVrSAEdl8BkeKZrMBln0pCCfjotCCxcCS9L6w,516
|
|
57
|
+
qcanvas/ui/qml_components/AttachmentsPane.qml,sha256=50UElZB598m230dgBbDx9WDvK3uS5PvbcAhzSDIuIKQ,196
|
|
58
|
+
qcanvas/ui/qml_components/CommentsList.ui.qml,sha256=l8uqDrqIGVeOIAHnn4rwQQGiedFXAdMFANzvcHflCJo,477
|
|
59
|
+
qcanvas/ui/qml_components/CommentsListDelegate.ui.qml,sha256=iI-8Byw9dEOcbB18kQ6LGBH9IMCdmoK4Ak2WgSxkx78,3172
|
|
60
|
+
qcanvas/ui/qml_components/CommentsListModel.qml,sha256=oEffdqXiavoO4zcyBu8aqIlR-0IYDQKli3aKlGUxltg,2230
|
|
61
|
+
qcanvas/ui/qml_components/CommentsPane.qml,sha256=ZatxphygIA4aPJ5nEkEdU9SG03sOCqItaG3IewLJUBE,185
|
|
62
|
+
qcanvas/ui/qml_components/DarkTheme.qml,sha256=cc9NltNQp9vzZeKItJEXCBUBzvvfDTC6y8nL3gKWMTY,222
|
|
63
|
+
qcanvas/ui/qml_components/DecoratedText.ui.qml,sha256=U4p_P6gXRBj1GKDe0azJlp9-fT8yFw3XVjQH76L8MQ0,1003
|
|
64
|
+
qcanvas/ui/qml_components/LightTheme.qml,sha256=ItN-3U9WiCUThIOlvYwGkTukx-ceHTGxHBqEZve__is,172
|
|
65
|
+
qcanvas/ui/qml_components/Spacer.ui.qml,sha256=RE86ASh90JUV82QLWV9FoD3pVzv9F_gHFNyDpk_Befo,78
|
|
66
|
+
qcanvas/ui/qml_components/ThemedRectangle.qml,sha256=9EIBZInRCTrO8vEqYLlIsWxa88PYHmNTgc1nqKiO7hY,653
|
|
67
|
+
qcanvas/ui/qml_components/__init__.py,sha256=ogGsI7ynuB0EhAeQRH7VJeJIYYwMza_AzFzjPlBmsVc,136
|
|
68
|
+
qcanvas/ui/qml_components/attachments_pane.py,sha256=PwvITNo9xwGKvqGYp6OkMO7MAeMJjOm9H_DajZzfM_E,2366
|
|
69
|
+
qcanvas/ui/qml_components/comments_pane.py,sha256=IJkaR5cn4Ez08nh7V_iZEY56ojHcxRRPRLKgiZirslo,2993
|
|
70
|
+
qcanvas/ui/qml_components/qml_bridge_types.py,sha256=iHyG9ACG7bj8X_fty4Qpd5oSTmcW3zaFZdSi_KNXymE,2725
|
|
71
|
+
qcanvas/ui/qml_components/qml_pane.py,sha256=KNWFJ1--hRpDSCjiZB8yMWFxQdbZFGDemXP09KGFMMo,698
|
|
72
|
+
qcanvas/ui/setup/__init__.py,sha256=QWt2lEyLqWG5QC-BmCBlYyi0LZsBfsQYbP0XkvqA2f8,77
|
|
73
|
+
qcanvas/ui/setup/setup_checker.py,sha256=gU70geojUyOTW_fNgH-GzpTMrtYXsLHWf2wUnFaezmA,444
|
|
74
|
+
qcanvas/ui/setup/setup_dialog.py,sha256=_-52R6B8UIpKWRQ5jqpypgJLdnm_aXrZ5cKtyAXq0JA,10730
|
|
75
|
+
qcanvas/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
|
+
qcanvas/util/auto_downloader.py,sha256=DO2TCNQ2idUoITqlxxAp1tY8C5Zy52nghjCE4hv49aw,1905
|
|
77
|
+
qcanvas/util/basic_fonts.py,sha256=TqaY2UchDseHDZYB-Bh6r3xRoRuc5S9lf8j-fMGGCYQ,249
|
|
78
|
+
qcanvas/util/context_dict.py,sha256=05TlRto_fzmwdUBOVFEPVNCnch4gDYys1fpuMwLhpto,315
|
|
79
|
+
qcanvas/util/file_icons.py,sha256=TKHITkkd2HKAWR7mBJuXc034l76Ptp1YXM_eeLbEKW8,1509
|
|
80
|
+
qcanvas/util/html_cleaner.py,sha256=U-UbZVX9x85gatOvxLsQXe2hL6x4I86eUKwkm0p159E,710
|
|
81
|
+
qcanvas/util/layouts.py,sha256=in7V6mzJIlnVc1DbvhpxA5fIYBIUIQT-OPa9dHUYIrI,1498
|
|
82
|
+
qcanvas/util/logs.py,sha256=VZKFITiW2WR2POEFVv5GRpEXic23Pzjehry-vH3g3Gk,138
|
|
83
|
+
qcanvas/util/paths.py,sha256=lLqQqOmREefJB8D1xARH3gCNNXXlSELlIuDQaCHpDr4,1373
|
|
84
|
+
qcanvas/util/qurl_util.py,sha256=6nTk8VkQjT87wMOXyZucPBYdT6TTYzfCTElqsypLZPg,200
|
|
85
|
+
qcanvas/util/runtime.py,sha256=EO1HFCN7dZbQtKHQOILuvjZFXGT7SzhlmPvU8ma95Z8,617
|
|
86
|
+
qcanvas/util/ui_tools.py,sha256=cdwDrtljxIpzikvUt4CAMC06kogJ4WfhSTsC3lXAcz4,3575
|
|
87
|
+
qcanvas/util/url_checker.py,sha256=HkNFixp1ARwc_YjYkpHb-IMTyuaC7CylvYCgDyo3sh4,136
|
|
88
|
+
qcanvas-2.0.0.dist-info/METADATA,sha256=pXItdPg8BAwpQzOiLjtBKDtPHeiAQblNVnNGAly2whs,2118
|
|
89
|
+
qcanvas-2.0.0.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
|
|
90
|
+
qcanvas-2.0.0.dist-info/entry_points.txt,sha256=hqG_g3MRYh_eLyQcDN4H3EXqmBia_fnJTJ-3nqZGzvY,40
|
|
91
|
+
qcanvas-2.0.0.dist-info/RECORD,,
|
qcanvas/app_start/__init__.py
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import logging
|
|
3
|
-
import sys
|
|
4
|
-
|
|
5
|
-
import qtpy
|
|
6
|
-
from qasync import QEventLoop
|
|
7
|
-
from qtpy.QtGui import QGuiApplication
|
|
8
|
-
from qtpy.QtWidgets import QApplication
|
|
9
|
-
|
|
10
|
-
import qcanvas.backend_connectors.qcanvas_task_master as task_master
|
|
11
|
-
from qcanvas.ui.main_ui.qcanvas_window import QCanvasWindow
|
|
12
|
-
from qcanvas.ui.setup import SetupDialog, setup_checker
|
|
13
|
-
from qcanvas.util import runtime, settings, themes
|
|
14
|
-
|
|
15
|
-
main_window = None
|
|
16
|
-
setup_window = None
|
|
17
|
-
|
|
18
|
-
_logger = logging.getLogger(__name__)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def _show_main():
|
|
22
|
-
global main_window
|
|
23
|
-
main_window = QCanvasWindow()
|
|
24
|
-
main_window.show()
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def _show_qt_api_name():
|
|
28
|
-
print(f"Using Qt bindings from {qtpy.API_NAME}")
|
|
29
|
-
_logger.info("Using Qt bindings from %s", qtpy.API_NAME)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def launch():
|
|
33
|
-
_show_qt_api_name()
|
|
34
|
-
|
|
35
|
-
app = QApplication(sys.argv)
|
|
36
|
-
|
|
37
|
-
if runtime.is_running_as_flatpak:
|
|
38
|
-
QGuiApplication.setDesktopFileName("io.github.qcanvas.QCanvasApp")
|
|
39
|
-
|
|
40
|
-
app.setApplicationName("QCanvas")
|
|
41
|
-
|
|
42
|
-
task_master.register()
|
|
43
|
-
themes.apply(settings.ui.theme)
|
|
44
|
-
|
|
45
|
-
event_loop = QEventLoop(app)
|
|
46
|
-
asyncio.set_event_loop(event_loop)
|
|
47
|
-
|
|
48
|
-
app_close_event = asyncio.Event()
|
|
49
|
-
app.aboutToQuit.connect(app_close_event.set)
|
|
50
|
-
|
|
51
|
-
if setup_checker.needs_setup():
|
|
52
|
-
setup_window = SetupDialog()
|
|
53
|
-
setup_window.show()
|
|
54
|
-
setup_window.closed.connect(_show_main)
|
|
55
|
-
else:
|
|
56
|
-
_show_main()
|
|
57
|
-
|
|
58
|
-
with event_loop:
|
|
59
|
-
event_loop.run_until_complete(app_close_event.wait())
|
qcanvas/icons/_update_icons.py
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# This file regenerates icons.qrc, rc_icons.py and the icons definition file based on the icons in dark/, light/ and universal/
|
|
2
|
-
|
|
3
|
-
import glob
|
|
4
|
-
import logging
|
|
5
|
-
import os
|
|
6
|
-
import subprocess
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
import xmltodict
|
|
10
|
-
|
|
11
|
-
_logger = logging.getLogger(__name__)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def remove_base_directory(path: str | Path) -> Path:
|
|
15
|
-
if isinstance(path, str):
|
|
16
|
-
path = Path(path)
|
|
17
|
-
|
|
18
|
-
return Path(*path.parts[1:])
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def generate_xml(all_icons: list[Path]) -> str:
|
|
22
|
-
xml_dict = {
|
|
23
|
-
"RCC": {
|
|
24
|
-
"@version": "1.0",
|
|
25
|
-
"qresource": {"@prefix": "icons/", "file": all_icons},
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return "<!DOCTYPE RCC>\n" + xmltodict.unparse(
|
|
30
|
-
xml_dict, pretty=True, full_document=False
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def generate_icon_defs(icons: list[Path]) -> str:
|
|
35
|
-
icons_base_removed = [remove_base_directory(icon) for icon in icons]
|
|
36
|
-
groups = group_icons_by_category(icons_base_removed)
|
|
37
|
-
classes = [
|
|
38
|
-
generate_group_class(group_name, icons) for group_name, icons in groups.items()
|
|
39
|
-
]
|
|
40
|
-
|
|
41
|
-
return f"""from .rc_icons import qt_resource_data as _ # Without this, icon data will not be loaded
|
|
42
|
-
from qtpy.QtGui import QIcon
|
|
43
|
-
from ._icon_type import UniversalIcon, ThemeIcon
|
|
44
|
-
|
|
45
|
-
""" + "\n\n".join(
|
|
46
|
-
classes
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def group_icons_by_category(icons: list[Path]) -> dict[str, set[Path]]:
|
|
51
|
-
groups: dict[str, set[Path]] = {}
|
|
52
|
-
|
|
53
|
-
for icon in icons:
|
|
54
|
-
icon_category = icon.parts[0]
|
|
55
|
-
groups.setdefault(icon_category, set())
|
|
56
|
-
groups[icon_category].add(icon)
|
|
57
|
-
|
|
58
|
-
return groups
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def generate_group_class(group_name: str, icons: set[Path]) -> str:
|
|
62
|
-
# pascal_case_class_name = "".join([part.title() for part in group_name.split("_")])
|
|
63
|
-
lines = ["# noinspection PyPep8Naming", f"class {group_name}:"]
|
|
64
|
-
|
|
65
|
-
for icon in sorted(icons):
|
|
66
|
-
path_no_ext = os.path.splitext(icon)[0]
|
|
67
|
-
lines.append(f' {icon.stem} = QIcon.fromTheme("{path_no_ext}")')
|
|
68
|
-
|
|
69
|
-
return "\n".join(lines)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def run_rcc() -> None:
|
|
73
|
-
subprocess.run(["pyside6-rcc", "icons.qrc", "-o", "rc_icons.py"])
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def write(file_name: str, content: str) -> None:
|
|
77
|
-
with open(file_name, "w") as f:
|
|
78
|
-
f.write(content)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if __name__ == "__main__":
|
|
82
|
-
all_icons: list[Path] = [
|
|
83
|
-
Path(file) for file in glob.glob("**/*.svg", recursive=True)
|
|
84
|
-
]
|
|
85
|
-
all_icons.sort()
|
|
86
|
-
|
|
87
|
-
write("icons.qrc", generate_xml(all_icons))
|
|
88
|
-
write("__init__.py", generate_icon_defs(all_icons))
|
|
89
|
-
run_rcc()
|