Skip to content

Commit a013782

Browse files
committed
Find desktop directory more robust; add log console
1 parent a12cae0 commit a013782

File tree

2 files changed

+110
-10
lines changed

2 files changed

+110
-10
lines changed

log_console.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import sys
2+
import io
3+
from PyQt6.QtWidgets import QMainWindow, QPlainTextEdit
4+
from PyQt6.QtGui import QAction
5+
6+
"""When running a GUI application, it is useful to have a log console
7+
since the standard output and standard error streams are not visible.
8+
This module provides a log console that can be opened from the application's
9+
menu bar. It is a simple text window that displays the output of sys.stdout
10+
and sys.stderr. The log console is not shown by default, but can be opened
11+
from the application's menu bar.
12+
"""
13+
14+
class ConsoleOutputStream(io.TextIOBase):
15+
def __init__(self):
16+
self.log_console = QPlainTextEdit()
17+
self.log_console.setReadOnly(True)
18+
self.log_console_window = QMainWindow()
19+
self.log_console_window.setCentralWidget(self.log_console)
20+
self.log_console_window.setGeometry(0, 300, 600, 300)
21+
screen_geometry = self.log_console_window.screen().geometry()
22+
screen_height = screen_geometry.height()
23+
window_geometry = self.log_console_window.geometry()
24+
window_height = window_geometry.height()
25+
self.log_console_window.setGeometry(0, screen_height - window_height, 600, 300)
26+
self.log_console_window.setWindowTitle('Log Console')
27+
# Autoscroll to the bottom
28+
self.log_console.verticalScrollBar().rangeChanged.connect(
29+
lambda: self.log_console.verticalScrollBar().setValue(
30+
self.log_console.verticalScrollBar().maximum()))
31+
# Should the application ever crash, show the log console
32+
sys.excepthook = self.open_log_console
33+
34+
def write(self, s):
35+
# Ignore whitespace
36+
if s.isspace():
37+
return
38+
# Remove newline characters; does not seem to work
39+
s = s.rstrip()
40+
self.log_console.appendHtml(s)
41+
42+
def add_menu_items(self, menu, parent):
43+
menu.addSeparator()
44+
log_console_action = QAction('Open Log Console', parent)
45+
log_console_action.triggered.connect(self.open_log_console)
46+
menu.addAction(log_console_action)
47+
48+
def open_log_console(self):
49+
if self.log_console_window.isVisible():
50+
return
51+
self.log_console_window.show()
52+
53+
class Tee(object):
54+
def __init__(self, stream1, stream2):
55+
self.stream1 = stream1
56+
self.stream2 = stream2
57+
58+
def write(self, data):
59+
self.stream1.write(data)
60+
self.stream2.write(data)
61+
62+
def flush(self):
63+
self.stream1.flush()
64+
self.stream2.flush()
65+
66+
"""app.log_console = log_console.ConsoleOutputStream()
67+
sys.stdout = log_console.Tee(sys.stdout, app.log_console)
68+
sys.stderr = log_console.Tee(sys.stderr, app.log_console)"""

spatial.py

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ def __init__(self, path=None, is_desktop_window=False):
115115
self.timer.start(5000)
116116
self.update_status_bar()
117117

118-
119118
# Watch for changes in the directory
120119
self.file_watcher = QFileSystemWatcher()
121120
self.file_watcher.directoryChanged.connect(self.directory_changed)
@@ -254,8 +253,6 @@ def init_menu_bar(self):
254253
up_and_close_current_action.setShortcut("Shift+Ctrl+Up")
255254
up_and_close_current_action.triggered.connect(self.open_parent_and_close_current)
256255
if not os.path.exists(parent) or os.path.normpath(self.path) == os.path.normpath(QDir.rootPath()):
257-
# or (os.path.normpath(os.path.dirname(self.path)) == os.path.normpath(QDir.homePath()) and os.path.basename(self.path) == "Desktop") \
258-
# or (os.path.normpath(os.path.dirname(os.path.dirname(self.path))) == os.path.normpath(QDir.homePath()) and os.path.basename(os.path.dirname(self.path)) == "Desktop"):
259256
up_action.setDisabled(True)
260257
up_and_close_current_action.setDisabled(True)
261258
if self.is_desktop_window == True:
@@ -272,7 +269,7 @@ def init_menu_bar(self):
272269
go_menu.addAction(start_menu_action)
273270
# View Menu
274271
view_menu = self.menu_bar.addMenu("View")
275-
if os.path.normpath(os.path.dirname(self.path)) == os.path.normpath(QDir.homePath()) and os.path.basename(self.path) == "Desktop":
272+
if os.path.normpath(self.path) == get_desktop_directory():
276273
align_items_desktop_action = QAction("Align Items", self)
277274
align_items_desktop_action.triggered.connect(self.align_items_desktop)
278275
view_menu.addAction(align_items_desktop_action)
@@ -293,9 +290,13 @@ def init_menu_bar(self):
293290

294291
# Help Menu
295292
help_menu = self.menu_bar.addMenu("Help")
293+
296294
about_action = QAction("About", self)
297295
about_action.triggered.connect(self.show_about)
298296
help_menu.addAction(about_action)
297+
help_menu.addSeparator
298+
if "log_console" in sys.modules:
299+
app.log_console.add_menu_items(help_menu, self)
299300

300301
def open_parent(self):
301302
# TODO: Detect whether the Shift key is pressed; if yes; if yes, close the current window if it is not the fullscreen desktop window
@@ -329,7 +330,7 @@ def adjust_window_size(self):
329330
self.resize(max_x, max_y)
330331

331332
def populate_items(self):
332-
if os.path.normpath(os.path.dirname(self.path)) == os.path.normpath(QDir.homePath()) and os.path.basename(self.path) == "Desktop":
333+
if os.path.normpath(self.path) == get_desktop_directory():
333334

334335
# Add every disk in the system
335336
print("Adding disks")
@@ -359,7 +360,7 @@ def populate_items(self):
359360
if entry == app.desktop_settings_file:
360361
continue
361362
# ~/Desktop is a special case; we don't want to show it
362-
if self.path == QDir.homePath() and entry == "Desktop":
363+
if self.path == os.path.basename(get_desktop_directory()) and entry == "Desktop":
363364
continue
364365
entry_path = os.path.join(self.path, entry)
365366
is_directory = os.path.isdir(entry_path)
@@ -608,6 +609,8 @@ def dropEvent(self, event):
608609
event.ignore()
609610

610611
def align_items(self):
612+
if not self.items:
613+
return
611614
num_columns = self.width() // self.item_width_for_positioning
612615
current_column = 0
613616
current_row = 0
@@ -641,6 +644,8 @@ def align_items(self):
641644
self.update_container_size()
642645

643646
def align_items_staggered(self):
647+
if not self.items:
648+
return
644649
num_columns = self.width() // self.item_width_for_positioning
645650
line_height = int(self.line_height - 0.5 * app.icon_size)
646651
current_column = 0
@@ -686,6 +691,8 @@ def align_items_staggered(self):
686691
self.update_container_size()
687692

688693
def align_items_desktop(self):
694+
if not self.items:
695+
return
689696
num_rows = (self.height() // self.line_height ) - 1
690697
current_column = 0
691698
current_row = 0
@@ -719,6 +726,8 @@ def align_items_desktop(self):
719726
current_column += 1
720727

721728
def align_items_circle(self):
729+
if not self.items:
730+
return
722731
radius = self.width() // 2 - self.horizontal_spacing - self.item_width_for_positioning // 2
723732

724733
# Calculate the center of the circle
@@ -767,7 +776,8 @@ def __init__(self, path, is_directory, position, parent=None):
767776
self.position = position
768777

769778
icon_provider = QFileIconProvider()
770-
if self.path == os.path.normpath(os.path.join(QDir.homePath(), "Desktop", app.trash_name)):
779+
# Trash
780+
if self.path == os.path.normpath(get_desktop_directory() + "/" + app.trash_name):
771781
icon = icon_provider.icon(QFileIconProvider.IconType.Trashcan).pixmap(app.icon_size, app.icon_size)
772782
else:
773783
icon = icon_provider.icon(QFileInfo(self.path)).pixmap(app.icon_size, app.icon_size)
@@ -947,6 +957,17 @@ def open(self, event):
947957
else:
948958
os.system(f"xdg-open \"{self.path}\"")
949959

960+
def get_desktop_directory():
961+
"""Get the desktop directory of the user."""
962+
if sys.platform == "win32":
963+
from win32com.client import Dispatch
964+
shell = Dispatch("WScript.Shell")
965+
desktop = os.path.normpath(shell.SpecialFolders("Desktop"))
966+
else:
967+
desktop = QDir.homePath() + "/Desktop"
968+
return os.path.normpath(desktop)
969+
970+
950971
if __name__ == "__main__":
951972
app = QApplication(sys.argv)
952973
if sys.platform == "win32":
@@ -955,10 +976,22 @@ def open(self, event):
955976
app.desktop_settings_file = ".DS_Spatial"
956977
app.trash_name = "Trash"
957978
app.icon_size = 32
958-
979+
980+
# Output not only to the console but also to the GUI
981+
try:
982+
import log_console
983+
except ImportError:
984+
pass
985+
if "log_console" in sys.modules:
986+
app.log_console = log_console.ConsoleOutputStream()
987+
sys.stdout = log_console.Tee(sys.stdout, app.log_console)
988+
sys.stderr = log_console.Tee(sys.stderr, app.log_console)
989+
990+
991+
959992
for screen in QApplication.screens():
960993
# TODO: Possibly only create the desktop window on the primary screen and just show a background image on the other screens
961-
desktop = SpatialFiler(os.path.normpath(QDir.homePath() + "/Desktop"), is_desktop_window = True)
994+
desktop = SpatialFiler(get_desktop_directory(), is_desktop_window = True)
962995
desktop.move(screen.geometry().x(), screen.geometry().y())
963996
desktop.resize(screen.geometry().width(), screen.geometry().height())
964997
desktop.setWindowFlags(Qt.WindowType.FramelessWindowHint)
@@ -978,7 +1011,6 @@ def open(self, event):
9781011
windows_wallpaper_path = os.path.normpath(shell.RegRead("HKEY_CURRENT_USER\\Control Panel\\Desktop\\Wallpaper")).replace("\\", "/")
9791012
print("Windows wallpaper path:", windows_wallpaper_path)
9801013
if windows_wallpaper_path != "." and os.path.exists(windows_wallpaper_path):
981-
# Set the background image of the window
9821014
p = desktop.container.palette()
9831015
p.setBrush(desktop.container.backgroundRole(), QBrush(QPixmap(windows_wallpaper_path).scaled(desktop.width(), desktop.height(), Qt.AspectRatioMode.KeepAspectRatioByExpanding)))
9841016
desktop.container.setPalette(p)

0 commit comments

Comments
 (0)