@@ -16,8 +16,8 @@ def __init__(self, parent=None):
1616
1717 title_bar = QWidget ()
1818 title_bar_layout = QHBoxLayout (title_bar )
19- title_bar_layout .setContentsMargins (5 , 0 , 5 , 0 )
20- title_bar_layout .setSpacing (1 )
19+ title_bar_layout .setContentsMargins (5 , 5 , 5 , 0 )
20+ title_bar_layout .setSpacing (5 )
2121
2222 title_bar_layout .addStretch ()
2323
@@ -33,34 +33,42 @@ def __init__(self, parent=None):
3333
3434 self .back_button = QPushButton ("◀" )
3535 self .forward_button = QPushButton ("▶" )
36+ self .refresh_button = QPushButton ("⟳" )
3637 self .maximize_button = QPushButton (icon = self .maximize_icon )
3738 self .open_log_button = QPushButton (icon = open_log_icon )
3839
3940 self .back_button .setObjectName ("DockTitleBarButton" )
4041 self .forward_button .setObjectName ("DockTitleBarButton" )
42+ self .refresh_button .setObjectName ("DockTitleBarButton" )
4143 self .maximize_button .setObjectName ("DockTitleBarButton" )
4244 self .open_log_button .setObjectName ("DockTitleBarButton" )
4345
4446 self .back_button .hide ()
4547 self .forward_button .hide ()
48+ self .refresh_button .hide ()
4649
4750 title_bar_layout .addWidget (self .back_button )
4851 title_bar_layout .addWidget (self .forward_button )
52+ title_bar_layout .addWidget (self .refresh_button )
4953 title_bar_layout .addWidget (self .open_log_button )
5054 title_bar_layout .addWidget (self .maximize_button )
5155
5256 self .back_button .setFlat (True )
5357 self .forward_button .setFlat (True )
58+ self .refresh_button .setFlat (True )
5459 self .open_log_button .setFlat (True )
5560 self .maximize_button .setFlat (True )
5661
5762 self .back_button .setToolTip ("Go Back (Alt+Left)" )
5863 self .forward_button .setToolTip ("Go Forward (Alt+Right)" )
64+ self .refresh_button .setToolTip ("Refresh (F5)" )
5965 self .open_log_button .setToolTip ("Open Log File" )
6066 self .maximize_button .setToolTip ("Maximize/Restore Dock (Ctrl+M)" )
6167
6268 self .setTitleBarWidget (title_bar )
6369 self .maximize_button .clicked .connect (self .toggle_maximize )
70+ self .refresh_button .clicked .connect (self .refresh_current_view )
71+
6472
6573 container = QWidget ()
6674 layout = QVBoxLayout (container )
@@ -80,17 +88,13 @@ def __init__(self, parent=None):
8088 self .tabs .tabBar ().setTabButton (0 , QTabBar .ButtonPosition .RightSide , None )
8189 self .tabs .currentChanged .connect (self .on_tab_changed )
8290
83- self .log_polling_timer = QTimer (self )
84- self .log_polling_timer .timeout .connect (self ._poll_active_log )
85-
8691 self ._warmup_web_engine ()
8792
8893 def get_console (self ):
8994 return self .console
9095
9196 def open_log_tab (self , filepath , title ):
9297 report_view = QWebEngineView ()
93- report_view .loadFinished .connect (self ._scroll_log )
9498 report_view .setUrl (QUrl .fromLocalFile (filepath ))
9599
96100 index = self .tabs .addTab (report_view , title )
@@ -120,6 +124,7 @@ def on_tab_changed(self, index):
120124 if isinstance (current_widget , QWebEngineView ):
121125 self .back_button .show ()
122126 self .forward_button .show ()
127+ self .refresh_button .show ()
123128
124129 page = current_widget .page ()
125130
@@ -135,6 +140,7 @@ def on_tab_changed(self, index):
135140 else :
136141 self .back_button .hide ()
137142 self .forward_button .hide ()
143+ self .refresh_button .hide ()
138144
139145 def toggle_maximize (self ):
140146 main_window = self .parent ()
@@ -175,40 +181,38 @@ def _update_forward_button_status(self):
175181 page = current_widget .page ()
176182 self .forward_button .setEnabled (page .action (QWebEnginePage .WebAction .Forward ).isEnabled ())
177183
184+ def refresh_current_view (self ):
185+ current_widget = self .tabs .currentWidget ()
186+ if isinstance (current_widget , QWebEngineView ):
187+ def get_scroll_and_refresh (scroll_y ):
188+ url = current_widget .url ().toLocalFile ()
189+ if not url :
190+ return
191+
192+ try :
193+ with open (url , 'r' , encoding = 'utf-8' ) as f :
194+ new_html = f .read ()
195+
196+ js_html = new_html .replace ('\\ ' , '\\ \\ ' ).replace ('`' , '\\ `' ).replace ('$' , '\\ $' )
197+
198+ js_code = f"""
199+ document.documentElement.innerHTML = `{ js_html } `;
200+ window.scrollTo(0, { scroll_y } );
201+ """
202+ current_widget .page ().runJavaScript (js_code )
203+
204+ except FileNotFoundError :
205+ current_widget .reload () # Fallback
206+
207+ current_widget .page ().runJavaScript ("window.scrollY;" , 0 , get_scroll_and_refresh )
208+
178209 def is_dock_maximized (self ):
179210 return self .is_maximized
180211
212+
181213 def _warmup_web_engine (self ):
182214 temp_view = QWebEngineView ()
183215 temp_view .deleteLater ()
184216
185- def _scroll_log (self , ok ):
186- if not ok :
187- return
188-
189- view = self .sender ()
190- if not view :
191- return
192-
193- def do_scroll ():
194- try :
195- js_code = "window.scrollTo(0, document.body.scrollHeight);"
196- view .page ().runJavaScript (js_code )
197- except RuntimeError as e :
198- if "has been deleted" in str (e ):
199- pass
200- else :
201- raise
202-
203- QTimer .singleShot (50 , do_scroll )
204-
205- def start_log_polling (self , interval_ms = 1000 ):
206- self .log_polling_timer .start (interval_ms )
207217
208- def stop_log_polling (self ):
209- self .log_polling_timer .stop ()
210218
211- def _poll_active_log (self ):
212- current_widget = self .tabs .currentWidget ()
213- if isinstance (current_widget , QWebEngineView ):
214- current_widget .reload ()
0 commit comments