Merge 7060e7682c into 7e3df43463
This commit is contained in:
commit
02e61e5008
|
|
@ -127,6 +127,7 @@ class TabData:
|
||||||
open_target: usertypes.ClickTarget = usertypes.ClickTarget.normal
|
open_target: usertypes.ClickTarget = usertypes.ClickTarget.normal
|
||||||
override_target: Optional[usertypes.ClickTarget] = None
|
override_target: Optional[usertypes.ClickTarget] = None
|
||||||
pinned: bool = False
|
pinned: bool = False
|
||||||
|
custom_title: Optional[str] = None
|
||||||
fullscreen: bool = False
|
fullscreen: bool = False
|
||||||
netrc_used: bool = False
|
netrc_used: bool = False
|
||||||
input_mode: usertypes.KeyMode = usertypes.KeyMode.normal
|
input_mode: usertypes.KeyMode = usertypes.KeyMode.normal
|
||||||
|
|
@ -1132,12 +1133,13 @@ class AbstractTab(QWidget):
|
||||||
qtutils.ensure_valid(url)
|
qtutils.ensure_valid(url)
|
||||||
url_string = url.toDisplayString()
|
url_string = url.toDisplayString()
|
||||||
log.webview.debug("Going to start loading: {}".format(url_string))
|
log.webview.debug("Going to start loading: {}".format(url_string))
|
||||||
self.title_changed.emit(url_string)
|
if not self.title() and not self.data.custom_title:
|
||||||
|
self.title_changed.emit(url_string)
|
||||||
|
|
||||||
@pyqtSlot(QUrl)
|
@pyqtSlot(QUrl)
|
||||||
def _on_url_changed(self, url: QUrl) -> None:
|
def _on_url_changed(self, url: QUrl) -> None:
|
||||||
"""Update title when URL has changed and no title is available."""
|
"""Update title when URL has changed and no title is available."""
|
||||||
if url.isValid() and not self.title():
|
if url.isValid() and not self.title() and not self.data.custom_title:
|
||||||
self.title_changed.emit(url.toDisplayString())
|
self.title_changed.emit(url.toDisplayString())
|
||||||
self.url_changed.emit(url)
|
self.url_changed.emit(url)
|
||||||
|
|
||||||
|
|
@ -1189,7 +1191,7 @@ class AbstractTab(QWidget):
|
||||||
|
|
||||||
self.load_finished.emit(ok)
|
self.load_finished.emit(ok)
|
||||||
|
|
||||||
if not self.title():
|
if not self.title() and not self.data.custom_title:
|
||||||
self.title_changed.emit(self.url().toDisplayString())
|
self.title_changed.emit(self.url().toDisplayString())
|
||||||
|
|
||||||
self.zoom.reapply()
|
self.zoom.reapply()
|
||||||
|
|
@ -1285,9 +1287,25 @@ class AbstractTab(QWidget):
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def title(self) -> str:
|
def raw_title(self) -> str:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def title(self) -> str:
|
||||||
|
return self.data.custom_title or self.raw_title()
|
||||||
|
|
||||||
|
def set_title(self, title: str) -> None:
|
||||||
|
"""Set a custom tab's title, or reset it if empty is passed.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
title: A custom tab's title
|
||||||
|
"""
|
||||||
|
if title:
|
||||||
|
self.data.custom_title = title
|
||||||
|
self.title_changed.emit(title)
|
||||||
|
else:
|
||||||
|
self.data.custom_title = None
|
||||||
|
self.title_changed.emit(self.raw_title())
|
||||||
|
|
||||||
def icon(self) -> QIcon:
|
def icon(self) -> QIcon:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -258,6 +258,24 @@ class CommandDispatcher:
|
||||||
|
|
||||||
self._tabbed_browser.tab_close_prompt_if_pinned(tab, force, close)
|
self._tabbed_browser.tab_close_prompt_if_pinned(tab, force, close)
|
||||||
|
|
||||||
|
@cmdutils.register(instance='command-dispatcher', scope='window',
|
||||||
|
name='tab-title')
|
||||||
|
@cmdutils.argument('count', value=cmdutils.Value.count)
|
||||||
|
@cmdutils.argument('title')
|
||||||
|
def tab_title(self, count=None, title=None):
|
||||||
|
"""Set/Unset the current/[count]th tab's title.
|
||||||
|
|
||||||
|
Set the text to empty to unset the tab's title.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
count: The tab index to set or unset tab's title, or None
|
||||||
|
title: The tab title to renamed to, or empty to reset it
|
||||||
|
"""
|
||||||
|
tab = self._cntwidget(count)
|
||||||
|
if tab is None:
|
||||||
|
return
|
||||||
|
tab.set_title(title or '')
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window',
|
@cmdutils.register(instance='command-dispatcher', scope='window',
|
||||||
name='tab-pin')
|
name='tab-pin')
|
||||||
@cmdutils.argument('count', value=cmdutils.Value.count)
|
@cmdutils.argument('count', value=cmdutils.Value.count)
|
||||||
|
|
@ -426,6 +444,7 @@ class CommandDispatcher:
|
||||||
newtab.history.private_api.deserialize(history)
|
newtab.history.private_api.deserialize(history)
|
||||||
newtab.zoom.set_factor(curtab.zoom.factor())
|
newtab.zoom.set_factor(curtab.zoom.factor())
|
||||||
|
|
||||||
|
newtab.set_title(curtab.data.custom_title)
|
||||||
newtab.set_pinned(curtab.data.pinned)
|
newtab.set_pinned(curtab.data.pinned)
|
||||||
return newtab
|
return newtab
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1406,7 +1406,7 @@ class WebEngineTab(browsertab.AbstractTab):
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self._widget.stop()
|
self._widget.stop()
|
||||||
|
|
||||||
def title(self):
|
def raw_title(self):
|
||||||
return self._widget.title()
|
return self._widget.title()
|
||||||
|
|
||||||
def renderer_process_pid(self) -> int:
|
def renderer_process_pid(self) -> int:
|
||||||
|
|
@ -1724,6 +1724,12 @@ class WebEngineTab(browsertab.AbstractTab):
|
||||||
else:
|
else:
|
||||||
selection.selectNone()
|
selection.selectNone()
|
||||||
|
|
||||||
|
def _on_title_changed(self, title):
|
||||||
|
"""Handle title updates."""
|
||||||
|
if self.data.custom_title:
|
||||||
|
return
|
||||||
|
self.title_changed.emit(title)
|
||||||
|
|
||||||
def _connect_signals(self):
|
def _connect_signals(self):
|
||||||
view = self._widget
|
view = self._widget
|
||||||
page = view.page()
|
page = view.page()
|
||||||
|
|
@ -1742,7 +1748,7 @@ class WebEngineTab(browsertab.AbstractTab):
|
||||||
page.printRequested.connect(self._on_print_requested)
|
page.printRequested.connect(self._on_print_requested)
|
||||||
page.selectClientCertificate.connect(self._on_select_client_certificate)
|
page.selectClientCertificate.connect(self._on_select_client_certificate)
|
||||||
|
|
||||||
view.titleChanged.connect(self.title_changed)
|
view.titleChanged.connect(self._on_title_changed)
|
||||||
view.urlChanged.connect(self._on_url_changed)
|
view.urlChanged.connect(self._on_url_changed)
|
||||||
view.renderProcessTerminated.connect(
|
view.renderProcessTerminated.connect(
|
||||||
self._on_render_process_terminated)
|
self._on_render_process_terminated)
|
||||||
|
|
|
||||||
|
|
@ -927,7 +927,7 @@ class WebKitTab(browsertab.AbstractTab):
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self._widget.stop()
|
self._widget.stop()
|
||||||
|
|
||||||
def title(self):
|
def raw_title(self):
|
||||||
return self._widget.title()
|
return self._widget.title()
|
||||||
|
|
||||||
def renderer_process_pid(self) -> Optional[int]:
|
def renderer_process_pid(self) -> Optional[int]:
|
||||||
|
|
@ -1017,6 +1017,12 @@ class WebKitTab(browsertab.AbstractTab):
|
||||||
def _on_ssl_errors(self, reply):
|
def _on_ssl_errors(self, reply):
|
||||||
self._insecure_hosts.add(reply.url().host())
|
self._insecure_hosts.add(reply.url().host())
|
||||||
|
|
||||||
|
def _on_title_changed(self, title):
|
||||||
|
"""Handle title updates."""
|
||||||
|
if self.data.custom_title:
|
||||||
|
return
|
||||||
|
self.title_changed.emit(title)
|
||||||
|
|
||||||
def _connect_signals(self):
|
def _connect_signals(self):
|
||||||
view = self._widget
|
view = self._widget
|
||||||
page = view.page()
|
page = view.page()
|
||||||
|
|
@ -1031,7 +1037,7 @@ class WebKitTab(browsertab.AbstractTab):
|
||||||
self._on_load_started)
|
self._on_load_started)
|
||||||
view.scroll_pos_changed.connect(self.scroller.perc_changed)
|
view.scroll_pos_changed.connect(self.scroller.perc_changed)
|
||||||
view.titleChanged.connect( # type: ignore[attr-defined]
|
view.titleChanged.connect( # type: ignore[attr-defined]
|
||||||
self.title_changed)
|
self._on_title_changed)
|
||||||
view.urlChanged.connect( # type: ignore[attr-defined]
|
view.urlChanged.connect( # type: ignore[attr-defined]
|
||||||
self._on_url_changed)
|
self._on_url_changed)
|
||||||
view.shutting_down.connect(self.shutting_down)
|
view.shutting_down.connect(self.shutting_down)
|
||||||
|
|
|
||||||
|
|
@ -3707,6 +3707,7 @@ bindings.default:
|
||||||
K: tab-prev
|
K: tab-prev
|
||||||
<Ctrl-PgUp>: tab-prev
|
<Ctrl-PgUp>: tab-prev
|
||||||
gC: tab-clone
|
gC: tab-clone
|
||||||
|
tt: cmd-set-text -s :tab-title
|
||||||
r: reload
|
r: reload
|
||||||
<F5>: reload
|
<F5>: reload
|
||||||
R: reload -f
|
R: reload -f
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ class _UndoEntry:
|
||||||
history: bytes
|
history: bytes
|
||||||
index: int
|
index: int
|
||||||
pinned: bool
|
pinned: bool
|
||||||
|
title: Optional[str]
|
||||||
created_at: datetime.datetime = dataclasses.field(
|
created_at: datetime.datetime = dataclasses.field(
|
||||||
default_factory=datetime.datetime.now)
|
default_factory=datetime.datetime.now)
|
||||||
|
|
||||||
|
|
@ -516,6 +517,7 @@ class TabbedBrowser(QWidget):
|
||||||
entry = _UndoEntry(url=tab.url(),
|
entry = _UndoEntry(url=tab.url(),
|
||||||
history=history_data,
|
history=history_data,
|
||||||
index=idx,
|
index=idx,
|
||||||
|
title=tab.data.custom_title,
|
||||||
pinned=tab.data.pinned)
|
pinned=tab.data.pinned)
|
||||||
if new_undo or not self.undo_stack:
|
if new_undo or not self.undo_stack:
|
||||||
self.undo_stack.append([entry])
|
self.undo_stack.append([entry])
|
||||||
|
|
@ -563,6 +565,7 @@ class TabbedBrowser(QWidget):
|
||||||
newtab = self.tabopen(background=False, idx=entry.index)
|
newtab = self.tabopen(background=False, idx=entry.index)
|
||||||
|
|
||||||
newtab.history.private_api.deserialize(entry.history)
|
newtab.history.private_api.deserialize(entry.history)
|
||||||
|
newtab.set_title(entry.title or '')
|
||||||
newtab.set_pinned(entry.pinned)
|
newtab.set_pinned(entry.pinned)
|
||||||
newtab.setFocus()
|
newtab.setFocus()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,7 @@ class SessionManager(QObject):
|
||||||
data['scroll-pos'] = {'x': pos.x(), 'y': pos.y()}
|
data['scroll-pos'] = {'x': pos.x(), 'y': pos.y()}
|
||||||
|
|
||||||
data['pinned'] = tab.data.pinned
|
data['pinned'] = tab.data.pinned
|
||||||
|
data['custom_title'] = tab.data.custom_title
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
@ -412,6 +413,9 @@ class SessionManager(QObject):
|
||||||
if 'pinned' in histentry:
|
if 'pinned' in histentry:
|
||||||
new_tab.data.pinned = histentry['pinned']
|
new_tab.data.pinned = histentry['pinned']
|
||||||
|
|
||||||
|
if 'custom_title' in histentry:
|
||||||
|
new_tab.data.custom_title = histentry['custom_title']
|
||||||
|
|
||||||
if (config.val.session.lazy_restore and
|
if (config.val.session.lazy_restore and
|
||||||
histentry.get('active', False) and
|
histentry.get('active', False) and
|
||||||
not histentry['url'].startswith('qute://back')):
|
not histentry['url'].startswith('qute://back')):
|
||||||
|
|
@ -449,7 +453,10 @@ class SessionManager(QObject):
|
||||||
last_visited=last_visited)
|
last_visited=last_visited)
|
||||||
entries.append(entry)
|
entries.append(entry)
|
||||||
if active:
|
if active:
|
||||||
new_tab.title_changed.emit(histentry['title'])
|
if new_tab.data.custom_title:
|
||||||
|
new_tab.title_changed.emit(new_tab.data.custom_title)
|
||||||
|
else:
|
||||||
|
new_tab.title_changed.emit(histentry['title'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_tab.history.private_api.load_items(entries)
|
new_tab.history.private_api.load_items(entries)
|
||||||
|
|
@ -470,6 +477,8 @@ class SessionManager(QObject):
|
||||||
tab_to_focus = i
|
tab_to_focus = i
|
||||||
if new_tab.data.pinned:
|
if new_tab.data.pinned:
|
||||||
new_tab.set_pinned(True)
|
new_tab.set_pinned(True)
|
||||||
|
if new_tab.data.custom_title:
|
||||||
|
new_tab.set_title(new_tab.data.custom_title)
|
||||||
if tab_to_focus is not None:
|
if tab_to_focus is not None:
|
||||||
tabbed_browser.widget.setCurrentIndex(tab_to_focus)
|
tabbed_browser.widget.setCurrentIndex(tab_to_focus)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1925,6 +1925,136 @@ Feature: Tab management
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# :tab-title
|
||||||
|
|
||||||
|
Scenario: Set tab title
|
||||||
|
When I open data/title.html
|
||||||
|
And I open data/title.html in a new tab
|
||||||
|
And I run :tab-title renamed
|
||||||
|
Then the session should look like:
|
||||||
|
"""
|
||||||
|
windows:
|
||||||
|
- tabs:
|
||||||
|
- history:
|
||||||
|
- url: about:blank
|
||||||
|
- url: http://localhost:*/data/title.html
|
||||||
|
title: Test title
|
||||||
|
custom_title:
|
||||||
|
- active: true
|
||||||
|
history:
|
||||||
|
- url: http://localhost:*/data/title.html
|
||||||
|
title: Test title
|
||||||
|
custom_title: renamed
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Set specific tab title using count
|
||||||
|
When I open data/title.html
|
||||||
|
And I open data/title.html in a new tab
|
||||||
|
And I run :tab-title renamed with count 1
|
||||||
|
Then the session should look like:
|
||||||
|
"""
|
||||||
|
windows:
|
||||||
|
- tabs:
|
||||||
|
- history:
|
||||||
|
- url: about:blank
|
||||||
|
- url: http://localhost:*/data/title.html
|
||||||
|
title: Test title
|
||||||
|
custom_title: renamed
|
||||||
|
- active: true
|
||||||
|
history:
|
||||||
|
- url: http://localhost:*/data/title.html
|
||||||
|
title: Test title
|
||||||
|
custom_title:
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Set tab title with space
|
||||||
|
When I open data/title.html
|
||||||
|
And I open data/title.html in a new tab
|
||||||
|
And I run :tab-title 'a new title'
|
||||||
|
Then the session should look like:
|
||||||
|
"""
|
||||||
|
windows:
|
||||||
|
- tabs:
|
||||||
|
- history:
|
||||||
|
- url: about:blank
|
||||||
|
- url: http://localhost:*/data/title.html
|
||||||
|
title: Test title
|
||||||
|
custom_title:
|
||||||
|
- active: true
|
||||||
|
history:
|
||||||
|
- url: http://localhost:*/data/title.html
|
||||||
|
title: Test title
|
||||||
|
custom_title: a new title
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Custom tab title when navigated
|
||||||
|
When I open data/numbers/1.txt
|
||||||
|
And I run :tab-title 'a new title'
|
||||||
|
And I open data/title.html
|
||||||
|
Then the session should look like:
|
||||||
|
"""
|
||||||
|
windows:
|
||||||
|
- tabs:
|
||||||
|
- active: true
|
||||||
|
history:
|
||||||
|
- url: about:blank
|
||||||
|
- url: http://localhost:*/data/numbers/1.txt
|
||||||
|
custom_title: a new title
|
||||||
|
- url: http://localhost:*/data/title.html
|
||||||
|
title: Test title
|
||||||
|
custom_title: a new title
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Cloning a tab with a custom tab title
|
||||||
|
When I open data/title.html
|
||||||
|
And I open data/title.html in a new tab
|
||||||
|
And I run :tab-title 'a new title'
|
||||||
|
And I run :tab-clone
|
||||||
|
And I wait until data/title.html is loaded
|
||||||
|
Then the session should look like:
|
||||||
|
"""
|
||||||
|
windows:
|
||||||
|
- tabs:
|
||||||
|
- history:
|
||||||
|
- url: about:blank
|
||||||
|
- url: http://localhost:*/data/title.html
|
||||||
|
title: Test title
|
||||||
|
custom_title:
|
||||||
|
- history:
|
||||||
|
- url: http://localhost:*/data/title.html
|
||||||
|
title: Test title
|
||||||
|
custom_title: a new title
|
||||||
|
- active: true
|
||||||
|
history:
|
||||||
|
- url: http://localhost:*/data/title.html
|
||||||
|
title: Test title
|
||||||
|
custom_title: a new title
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Undo a tab with a custom tab title
|
||||||
|
When I open data/title.html
|
||||||
|
And I open data/title.html in a new tab
|
||||||
|
And I run :tab-title 'a new title'
|
||||||
|
And I run :tab-close --force
|
||||||
|
And I run :undo
|
||||||
|
And I wait until data/title.html is loaded
|
||||||
|
Then the session should look like:
|
||||||
|
"""
|
||||||
|
windows:
|
||||||
|
- tabs:
|
||||||
|
- history:
|
||||||
|
- url: about:blank
|
||||||
|
- url: http://localhost:*/data/title.html
|
||||||
|
title: Test title
|
||||||
|
custom_title:
|
||||||
|
- active: true
|
||||||
|
history:
|
||||||
|
- url: http://localhost:*/data/title.html
|
||||||
|
title: Test title
|
||||||
|
custom_title: a new title
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
Scenario: Focused webview after clicking link in bg
|
Scenario: Focused webview after clicking link in bg
|
||||||
When I open data/hints/link_input.html
|
When I open data/hints/link_input.html
|
||||||
And I run :click-element id qute-input-existing
|
And I run :click-element id qute-input-existing
|
||||||
|
|
|
||||||
|
|
@ -1413,12 +1413,15 @@ def test_undo_completion(tabbed_browser_stubs, info):
|
||||||
"""Test :undo completion."""
|
"""Test :undo completion."""
|
||||||
entry1 = tabbedbrowser._UndoEntry(url=QUrl('https://example.org/'),
|
entry1 = tabbedbrowser._UndoEntry(url=QUrl('https://example.org/'),
|
||||||
history=None, index=None, pinned=None,
|
history=None, index=None, pinned=None,
|
||||||
|
title=None,
|
||||||
created_at=datetime(2020, 1, 1))
|
created_at=datetime(2020, 1, 1))
|
||||||
entry2 = tabbedbrowser._UndoEntry(url=QUrl('https://example.com/'),
|
entry2 = tabbedbrowser._UndoEntry(url=QUrl('https://example.com/'),
|
||||||
history=None, index=None, pinned=None,
|
history=None, index=None, pinned=None,
|
||||||
|
title=None,
|
||||||
created_at=datetime(2020, 1, 2))
|
created_at=datetime(2020, 1, 2))
|
||||||
entry3 = tabbedbrowser._UndoEntry(url=QUrl('https://example.net/'),
|
entry3 = tabbedbrowser._UndoEntry(url=QUrl('https://example.net/'),
|
||||||
history=None, index=None, pinned=None,
|
history=None, index=None, pinned=None,
|
||||||
|
title=None,
|
||||||
created_at=datetime(2020, 1, 2))
|
created_at=datetime(2020, 1, 2))
|
||||||
|
|
||||||
# Most recently closed is at the end
|
# Most recently closed is at the end
|
||||||
|
|
@ -1453,7 +1456,7 @@ def undo_completion_retains_sort_order(tabbed_browser_stubs, info):
|
||||||
tabbedbrowser._UndoEntry(
|
tabbedbrowser._UndoEntry(
|
||||||
url=QUrl(f'https://example.org/{idx}'),
|
url=QUrl(f'https://example.org/{idx}'),
|
||||||
history=None, index=None, pinned=None,
|
history=None, index=None, pinned=None,
|
||||||
created_at=created_dt,
|
title=None, created_at=created_dt,
|
||||||
)
|
)
|
||||||
for idx in range(1, 11)
|
for idx in range(1, 11)
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue