Merge branch 'master' into jay/pintab
@ -7,11 +7,14 @@ environment:
|
|||||||
PYTHONUNBUFFERED: 1
|
PYTHONUNBUFFERED: 1
|
||||||
matrix:
|
matrix:
|
||||||
- TESTENV: py34
|
- TESTENV: py34
|
||||||
|
- TESTENV: py36-pyqt58
|
||||||
|
PYTHON: C:\Python36\python.exe
|
||||||
- TESTENV: unittests-frozen
|
- TESTENV: unittests-frozen
|
||||||
- TESTENV: pylint
|
- TESTENV: pylint
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- C:\Python27\python -u scripts\dev\ci\appveyor_install.py
|
- C:\Python27\python -u scripts\dev\ci\appveyor_install.py
|
||||||
|
- set PATH=%PATH%;C:\Python36
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- C:\Python34\Scripts\tox -e %TESTENV%
|
- C:\Python34\Scripts\tox -e %TESTENV%
|
||||||
|
2
.flake8
@ -35,9 +35,9 @@ max-complexity = 12
|
|||||||
putty-auto-ignore = True
|
putty-auto-ignore = True
|
||||||
putty-ignore =
|
putty-ignore =
|
||||||
/# pylint: disable=invalid-name/ : +N801,N806
|
/# pylint: disable=invalid-name/ : +N801,N806
|
||||||
/# pylint: disable=wildcard-import/ : +F403
|
|
||||||
/# pragma: no mccabe/ : +C901
|
/# pragma: no mccabe/ : +C901
|
||||||
tests/*/test_*.py : +D100,D101,D401
|
tests/*/test_*.py : +D100,D101,D401
|
||||||
|
tests/conftest.py : +F403
|
||||||
tests/unit/browser/webkit/test_history.py : +N806
|
tests/unit/browser/webkit/test_history.py : +N806
|
||||||
tests/helpers/fixtures.py : +N806
|
tests/helpers/fixtures.py : +N806
|
||||||
tests/unit/browser/webkit/http/test_content_disposition.py : +D400
|
tests/unit/browser/webkit/http/test_content_disposition.py : +D400
|
||||||
|
2
.github/ISSUE_TEMPLATE.md
vendored
@ -1,2 +1,2 @@
|
|||||||
<!-- If this is a bug report, please remember to mention your version info from
|
<!-- If this is a bug report, please remember to mention your version info from
|
||||||
the `qute:version` page or `qutebrowser --version` -->
|
`:open qute:version` or `qutebrowser --version` -->
|
||||||
|
@ -38,7 +38,8 @@ disable=no-self-use,
|
|||||||
suppressed-message,
|
suppressed-message,
|
||||||
too-many-return-statements,
|
too-many-return-statements,
|
||||||
duplicate-code,
|
duplicate-code,
|
||||||
wrong-import-position
|
wrong-import-position,
|
||||||
|
no-else-return
|
||||||
|
|
||||||
[BASIC]
|
[BASIC]
|
||||||
function-rgx=[a-z_][a-z0-9_]{2,50}$
|
function-rgx=[a-z_][a-z0-9_]{2,50}$
|
||||||
|
@ -21,18 +21,57 @@ Added
|
|||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
- New `:clear-messages` command to clear shown messages.
|
- New `:clear-messages` command to clear shown messages.
|
||||||
|
- New `ui -> keyhint-delay` setting to configure the delay until
|
||||||
|
the keyhint overlay pops up.
|
||||||
|
- New `-s` option for `:open` to force a HTTPS scheme.
|
||||||
|
- `:debug-log-filter` now accepts `none` as an argument to clear any log
|
||||||
|
filters.
|
||||||
|
- New `--debug-flag` argument which replaces `--debug-exit` and
|
||||||
|
`--pdb-postmortem`.
|
||||||
|
- New `tabs -> favicon-scale` option to scale up/down favicons.
|
||||||
|
|
||||||
Changed
|
Changed
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
|
||||||
|
- To prevent elaborate phishing attacks, the Punycode version is now shown in
|
||||||
|
addition to the decoded version for IDN domain names.
|
||||||
- When using QtWebEngine, the underlying Chromium version is now shown in the
|
- When using QtWebEngine, the underlying Chromium version is now shown in the
|
||||||
version info.
|
version info.
|
||||||
|
- Improved `qute:history` page with lazy loading
|
||||||
|
- Messages are now hidden when clicked
|
||||||
|
- Paths like `C:` are now treated as absolute paths on Windows for downloads,
|
||||||
|
and invalid paths are handled properly.
|
||||||
|
- PAC on QtWebKit now supports SOCKS5 as type.
|
||||||
|
- Comments in the config file are now before the individual
|
||||||
|
options instead of being before sections.
|
||||||
|
- The HTTP cache is disabled with QtWebKit on Qt 5.7.1 and 5.8 now as it leads
|
||||||
|
to frequent crashes due to a Qt bug.
|
||||||
|
- stdin is now closed immediately for processes spawned from qutebrowser
|
||||||
|
- When ui -> message-timeout is set to 0, messages are now never cleared.
|
||||||
|
- Middle/right-clicking the blank parts of the tab bar (when vertical) now
|
||||||
|
closes the current tab.
|
||||||
|
- With Qt 5.9, `content -> cookies-store` can now be set on QtWebEngine without
|
||||||
|
a restart.
|
||||||
|
- The adblocker now also blocks non-GET requests (e.g. POST)
|
||||||
|
- `:follow-selected` now also works with QtWebEngine
|
||||||
|
|
||||||
Fixed
|
Fixed
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
- Added a workaround for a black screen with QtWebEngine with some setups
|
- Added a workaround for a black screen with QtWebEngine with some setups
|
||||||
(requires PyOpenGL to be installed)
|
(the workaround requires PyOpenGL to be installed, but it's optional)
|
||||||
|
- Crash when trying to retry downloads with QtWebEngine
|
||||||
|
- Crash when cloning page without history
|
||||||
|
- Continuing a search after clearing it
|
||||||
|
- Crash when downloading a download resulting in a HTTP error
|
||||||
|
- Crash when pressing ctrl-c while a config error is shown
|
||||||
|
- Crash when the key config isn't writable
|
||||||
|
- Crash when unbinding an unbound key in the key config
|
||||||
|
- Crash when using `:debug-log-filter` when `--filter` wasn't given on startup.
|
||||||
|
- Crash with some invalid setting values
|
||||||
|
- Crash when cloning a view-source tab with QtWebEngine
|
||||||
|
- Various rare crashes
|
||||||
|
- Various styling issues with the tabbar and a crash with qt5ct
|
||||||
|
|
||||||
v0.10.1
|
v0.10.1
|
||||||
-------
|
-------
|
||||||
|
@ -42,6 +42,12 @@ be easy to solve]
|
|||||||
* https://github.com/qutebrowser/qutebrowser/labels/not%20code[Issues which
|
* https://github.com/qutebrowser/qutebrowser/labels/not%20code[Issues which
|
||||||
require little/no coding]
|
require little/no coding]
|
||||||
|
|
||||||
|
If you prefer C++ or Javascript to Python, see the relevant issues which involve
|
||||||
|
work in those languages:
|
||||||
|
|
||||||
|
* https://github.com/qutebrowser/qutebrowser/issues?utf8=%E2%9C%93&q=is%3Aopen%20is%3Aissue%20label%3Ac%2B%2B[C++] (mostly work on Qt, the library behind qutebrowser)
|
||||||
|
* https://github.com/qutebrowser/qutebrowser/issues?q=is%3Aopen+is%3Aissue+label%3Ajavascript[JavaScript]
|
||||||
|
|
||||||
There are also some things to do if you don't want to write code:
|
There are also some things to do if you don't want to write code:
|
||||||
|
|
||||||
* Help the community, e.g., on the mailinglist and the IRC channel.
|
* Help the community, e.g., on the mailinglist and the IRC channel.
|
||||||
|
28
FAQ.asciidoc
@ -124,6 +124,34 @@ When using quickmark, you can give them all names, like
|
|||||||
`:open foodrecipes`, you will see a list of all the food recipe sites,
|
`:open foodrecipes`, you will see a list of all the food recipe sites,
|
||||||
without having to remember the exact website title or address.
|
without having to remember the exact website title or address.
|
||||||
|
|
||||||
|
How do I use spell checking?::
|
||||||
|
Qutebrowser's support for spell checking is somewhat limited at the moment
|
||||||
|
(see https://github.com/qutebrowser/qutebrowser/issues/700[#700]), but it
|
||||||
|
can be done.
|
||||||
|
+
|
||||||
|
For QtWebKit:
|
||||||
|
|
||||||
|
. Install https://github.com/QupZilla/qtwebkit-plugins[qtwebkit-plugins].
|
||||||
|
. Note: with QtWebKit reloaded you may experience some issues. See
|
||||||
|
https://github.com/QupZilla/qtwebkit-plugins/issues/10[#10].
|
||||||
|
. The dictionary to use is taken from the `DICTIONARY` environment variable.
|
||||||
|
The default is `en_US`. For example to use Dutch spell check set `DICTIONARY`
|
||||||
|
to `nl_NL`; you can't use multiple dictionaries or change them at runtime at
|
||||||
|
the moment.
|
||||||
|
(also see the README file for `qtwebkit-plugins`).
|
||||||
|
. Remember to install the hunspell dictionaries if you don't have them already
|
||||||
|
(most distros should have packages for this).
|
||||||
|
|
||||||
|
+
|
||||||
|
For QtWebEngine:
|
||||||
|
|
||||||
|
. Not yet supported unfortunately :-( +
|
||||||
|
Adding it shouldn't be too hard though, since QtWebEngine 5.8 added an API for
|
||||||
|
this (see
|
||||||
|
https://github.com/qutebrowser/qutebrowser/issues/700#issuecomment-290780706[this
|
||||||
|
comment for a basic example]), so what are you waiting for and why aren't you
|
||||||
|
hacking qutebrowser yet?
|
||||||
|
|
||||||
== Troubleshooting
|
== Troubleshooting
|
||||||
|
|
||||||
Configuration not saved after modifying config.::
|
Configuration not saved after modifying config.::
|
||||||
|
@ -135,12 +135,42 @@ If video or sound don't seem to work, try installing the gstreamer plugins:
|
|||||||
On Gentoo
|
On Gentoo
|
||||||
---------
|
---------
|
||||||
|
|
||||||
qutebrowser is available in the main repository and can be installed with:
|
A version of qutebrowser is available in the main repository and can be installed with:
|
||||||
|
|
||||||
----
|
----
|
||||||
# emerge -av qutebrowser
|
# emerge -av qutebrowser
|
||||||
----
|
----
|
||||||
|
|
||||||
|
However it is suggested to install the Live version (-9999) to take advantage
|
||||||
|
of the newest features introduced.
|
||||||
|
|
||||||
|
First of all you need to edit your package.accept_keywords file to accept the live
|
||||||
|
version:
|
||||||
|
|
||||||
|
----
|
||||||
|
# nano /etc/portage/package.accept_keywords
|
||||||
|
----
|
||||||
|
|
||||||
|
And add the following line to it:
|
||||||
|
|
||||||
|
=www-client/qutebrowser-9999 **
|
||||||
|
|
||||||
|
Save the file and then install qutebrowser via
|
||||||
|
|
||||||
|
----
|
||||||
|
# emerge -av qutebrowser
|
||||||
|
----
|
||||||
|
|
||||||
|
Or rebuild your system if you already installed it.
|
||||||
|
|
||||||
|
To update to the last Live version, remember to do
|
||||||
|
|
||||||
|
----
|
||||||
|
# emerge -uDNav @live-rebuild @world
|
||||||
|
----
|
||||||
|
|
||||||
|
To include qutebrowser among the updates.
|
||||||
|
|
||||||
Make sure you have `python3_4` in your `PYTHON_TARGETS`
|
Make sure you have `python3_4` in your `PYTHON_TARGETS`
|
||||||
(`/etc/portage/make.conf`) and rebuild your system (`emerge -uDNav @world`) if
|
(`/etc/portage/make.conf`) and rebuild your system (`emerge -uDNav @world`) if
|
||||||
necessary.
|
necessary.
|
||||||
@ -192,19 +222,19 @@ On OpenBSD
|
|||||||
|
|
||||||
qutebrowser is in http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/www/qutebrowser/[OpenBSD ports].
|
qutebrowser is in http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/www/qutebrowser/[OpenBSD ports].
|
||||||
|
|
||||||
Manual install:
|
Install the package:
|
||||||
|
|
||||||
|
----
|
||||||
|
# pkg_add qutebrowser
|
||||||
|
----
|
||||||
|
|
||||||
|
Or alternatively, use the ports system :
|
||||||
|
|
||||||
----
|
----
|
||||||
# cd /usr/ports/www/qutebrowser
|
# cd /usr/ports/www/qutebrowser
|
||||||
# make install
|
# make install
|
||||||
----
|
----
|
||||||
|
|
||||||
Or alternatively if you're using `-current` (or OpenBSD 6.1 once it's been released):
|
|
||||||
|
|
||||||
----
|
|
||||||
# pkg_add qutebrowser
|
|
||||||
----
|
|
||||||
|
|
||||||
On Windows
|
On Windows
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
@ -24,6 +24,13 @@ on Python and PyQt5 and free software, licensed under the GPL.
|
|||||||
|
|
||||||
It was inspired by other browsers/addons like dwb and Vimperator/Pentadactyl.
|
It was inspired by other browsers/addons like dwb and Vimperator/Pentadactyl.
|
||||||
|
|
||||||
|
// QUTE_WEB_HIDE
|
||||||
|
**qutebrowser is currently running a crowdfunding campaign for its new
|
||||||
|
configuration system, allowing for per-domain settings and much more.**
|
||||||
|
|
||||||
|
See the link:https://www.kickstarter.com/projects/the-compiler/qutebrowser-v10-with-per-domain-settings?ref=6zw7qz[Kickstarter campaign] for more information!
|
||||||
|
// QUTE_WEB_HIDE_END
|
||||||
|
|
||||||
Screenshots
|
Screenshots
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
@ -71,7 +78,8 @@ https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser[mailinglist] at
|
|||||||
mailto:qutebrowser@lists.qutebrowser.org[].
|
mailto:qutebrowser@lists.qutebrowser.org[].
|
||||||
|
|
||||||
There's also a https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser-announce[announce-only mailinglist]
|
There's also a https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser-announce[announce-only mailinglist]
|
||||||
at mailto:qutebrowser-announce@lists.qutebrowser.org[].
|
at mailto:qutebrowser-announce@lists.qutebrowser.org[] (the announcements also
|
||||||
|
get sent to the general qutebrowser@ list).
|
||||||
|
|
||||||
Contributions / Bugs
|
Contributions / Bugs
|
||||||
--------------------
|
--------------------
|
||||||
@ -152,38 +160,41 @@ Contributors, sorted by the number of commits in descending order:
|
|||||||
* Lamar Pavel
|
* Lamar Pavel
|
||||||
* Marshall Lochbaum
|
* Marshall Lochbaum
|
||||||
* Bruno Oliveira
|
* Bruno Oliveira
|
||||||
|
* Martin Tournoij
|
||||||
|
* Imran Sobir
|
||||||
* Alexander Cogneau
|
* Alexander Cogneau
|
||||||
* Felix Van der Jeugt
|
* Felix Van der Jeugt
|
||||||
* Daniel Karbach
|
* Daniel Karbach
|
||||||
* Martin Tournoij
|
|
||||||
* Kevin Velghe
|
* Kevin Velghe
|
||||||
* Raphael Pierzina
|
* Raphael Pierzina
|
||||||
* Joel Torstensson
|
* Joel Torstensson
|
||||||
* Patric Schmitz
|
* Patric Schmitz
|
||||||
* Tarcisio Fedrizzi
|
* Tarcisio Fedrizzi
|
||||||
* Claude
|
* Claude
|
||||||
|
* Fritz Reichwald
|
||||||
* Corentin Julé
|
* Corentin Julé
|
||||||
* meles5
|
* meles5
|
||||||
* Philipp Hansch
|
* Philipp Hansch
|
||||||
* Imran Sobir
|
|
||||||
* Panagiotis Ktistakis
|
* Panagiotis Ktistakis
|
||||||
* Artur Shaik
|
* Artur Shaik
|
||||||
* Nathan Isom
|
* Nathan Isom
|
||||||
* Thorsten Wißmann
|
* Thorsten Wißmann
|
||||||
* Austin Anderson
|
* Austin Anderson
|
||||||
* Fritz Reichwald
|
|
||||||
* Jimmy
|
* Jimmy
|
||||||
* Niklas Haas
|
* Niklas Haas
|
||||||
* Maciej Wołczyk
|
* Maciej Wołczyk
|
||||||
* Spreadyy
|
* sandrosc
|
||||||
* Alexey "Averrin" Nabrodov
|
* Alexey "Averrin" Nabrodov
|
||||||
|
* pkill9
|
||||||
* nanjekyejoannah
|
* nanjekyejoannah
|
||||||
* avk
|
* avk
|
||||||
* ZDarian
|
* ZDarian
|
||||||
* Milan Svoboda
|
* Milan Svoboda
|
||||||
* John ShaggyTwoDope Jenkins
|
* John ShaggyTwoDope Jenkins
|
||||||
|
* Jay Kamat
|
||||||
* Clayton Craft
|
* Clayton Craft
|
||||||
* Peter Vilim
|
* Peter Vilim
|
||||||
|
* Jacob Sword
|
||||||
* knaggita
|
* knaggita
|
||||||
* Oliver Caldwell
|
* Oliver Caldwell
|
||||||
* Julian Weigt
|
* Julian Weigt
|
||||||
@ -205,7 +216,6 @@ Contributors, sorted by the number of commits in descending order:
|
|||||||
* David Vogt
|
* David Vogt
|
||||||
* Claire Cavanaugh
|
* Claire Cavanaugh
|
||||||
* rikn00
|
* rikn00
|
||||||
* pkill9
|
|
||||||
* kanikaa1234
|
* kanikaa1234
|
||||||
* haitaka
|
* haitaka
|
||||||
* Nick Ginther
|
* Nick Ginther
|
||||||
@ -239,8 +249,10 @@ Contributors, sorted by the number of commits in descending order:
|
|||||||
* adam
|
* adam
|
||||||
* Samir Benmendil
|
* Samir Benmendil
|
||||||
* Regina Hug
|
* Regina Hug
|
||||||
|
* Penaz
|
||||||
* Mathias Fussenegger
|
* Mathias Fussenegger
|
||||||
* Marcelo Santos
|
* Marcelo Santos
|
||||||
|
* Marcel Schilling
|
||||||
* Joel Bradshaw
|
* Joel Bradshaw
|
||||||
* Jean-Louis Fuchs
|
* Jean-Louis Fuchs
|
||||||
* Franz Fellner
|
* Franz Fellner
|
||||||
@ -253,6 +265,7 @@ Contributors, sorted by the number of commits in descending order:
|
|||||||
* haxwithaxe
|
* haxwithaxe
|
||||||
* evan
|
* evan
|
||||||
* dylan araps
|
* dylan araps
|
||||||
|
* caveman
|
||||||
* addictedtoflames
|
* addictedtoflames
|
||||||
* Xitian9
|
* Xitian9
|
||||||
* Vasilij Schneidermann
|
* Vasilij Schneidermann
|
||||||
@ -261,19 +274,18 @@ Contributors, sorted by the number of commits in descending order:
|
|||||||
* Tobias Werth
|
* Tobias Werth
|
||||||
* Tim Harder
|
* Tim Harder
|
||||||
* Thiago Barroso Perrotta
|
* Thiago Barroso Perrotta
|
||||||
|
* Steve Peak
|
||||||
* Sorokin Alexei
|
* Sorokin Alexei
|
||||||
* Simon Désaulniers
|
* Simon Désaulniers
|
||||||
* Rok Mandeljc
|
* Rok Mandeljc
|
||||||
* Noah Huesser
|
* Noah Huesser
|
||||||
* Moez Bouhlel
|
* Moez Bouhlel
|
||||||
* Matthias Lisin
|
* Matthias Lisin
|
||||||
* Marcel Schilling
|
|
||||||
* Lazlow Carmichael
|
* Lazlow Carmichael
|
||||||
* Kevin Wang
|
* Kevin Wang
|
||||||
* Ján Kobezda
|
* Ján Kobezda
|
||||||
* Johannes Martinsson
|
* Johannes Martinsson
|
||||||
* Jean-Christophe Petkovich
|
* Jean-Christophe Petkovich
|
||||||
* Jay Kamat
|
|
||||||
* Helen Sherwood-Taylor
|
* Helen Sherwood-Taylor
|
||||||
* HalosGhost
|
* HalosGhost
|
||||||
* Gregor Pohl
|
* Gregor Pohl
|
||||||
@ -281,9 +293,11 @@ Contributors, sorted by the number of commits in descending order:
|
|||||||
* Dietrich Daroch
|
* Dietrich Daroch
|
||||||
* Derek Sivers
|
* Derek Sivers
|
||||||
* Daniel Lu
|
* Daniel Lu
|
||||||
|
* Daniel Jakots
|
||||||
* Arseniy Seroka
|
* Arseniy Seroka
|
||||||
* Andy Balaam
|
* Andy Balaam
|
||||||
* Andreas Fischer
|
* Andreas Fischer
|
||||||
|
* Amos Bird
|
||||||
* Akselmo
|
* Akselmo
|
||||||
// QUTE_AUTHORS_END
|
// QUTE_AUTHORS_END
|
||||||
|
|
||||||
|
10
codecov.yml
@ -1,9 +1,7 @@
|
|||||||
|
coverage:
|
||||||
status:
|
status:
|
||||||
project:
|
project: off
|
||||||
enabled: no
|
patch: off
|
||||||
patch:
|
changes: off
|
||||||
enabled: no
|
|
||||||
changes:
|
|
||||||
enabled: no
|
|
||||||
|
|
||||||
comment: off
|
comment: off
|
||||||
|
@ -544,7 +544,7 @@ For `increment` and `decrement`, the number to change the URL by. For `up`, the
|
|||||||
|
|
||||||
[[open]]
|
[[open]]
|
||||||
=== open
|
=== open
|
||||||
Syntax: +:open [*--implicit*] [*--bg*] [*--tab*] [*--window*] ['url']+
|
Syntax: +:open [*--implicit*] [*--bg*] [*--tab*] [*--window*] [*--secure*] ['url']+
|
||||||
|
|
||||||
Open a URL in the current/[count]th tab.
|
Open a URL in the current/[count]th tab.
|
||||||
|
|
||||||
@ -559,6 +559,7 @@ If the URL contains newlines, each line gets opened in its own tab.
|
|||||||
* +*-b*+, +*--bg*+: Open in a new background tab.
|
* +*-b*+, +*--bg*+: Open in a new background tab.
|
||||||
* +*-t*+, +*--tab*+: Open in a new tab.
|
* +*-t*+, +*--tab*+: Open in a new tab.
|
||||||
* +*-w*+, +*--window*+: Open in a new window.
|
* +*-w*+, +*--window*+: Open in a new window.
|
||||||
|
* +*-s*+, +*--secure*+: Force HTTPS.
|
||||||
|
|
||||||
==== count
|
==== count
|
||||||
The tab index to open the URL in.
|
The tab index to open the URL in.
|
||||||
@ -1598,7 +1599,8 @@ Syntax: +:debug-log-filter 'filters'+
|
|||||||
Change the log filter for console logging.
|
Change the log filter for console logging.
|
||||||
|
|
||||||
==== positional arguments
|
==== positional arguments
|
||||||
* +'filters'+: A comma separated list of logger names.
|
* +'filters'+: A comma separated list of logger names. Can also be "none" to clear any existing filters.
|
||||||
|
|
||||||
|
|
||||||
[[debug-log-level]]
|
[[debug-log-level]]
|
||||||
=== debug-log-level
|
=== debug-log-level
|
||||||
@ -1653,7 +1655,7 @@ Syntax: +:debug-webaction 'action'+
|
|||||||
|
|
||||||
Execute a webaction.
|
Execute a webaction.
|
||||||
|
|
||||||
See http://doc.qt.io/qt-5/qwebpage.html#WebAction-enum for the available actions.
|
Available actions: http://doc.qt.io/archives/qt-5.5/qwebpage.html#WebAction-enum (WebKit) http://doc.qt.io/qt-5/qwebenginepage.html#WebAction-enum (WebEngine)
|
||||||
|
|
||||||
==== positional arguments
|
==== positional arguments
|
||||||
* +'action'+: The action to execute, e.g. MoveToNextChar.
|
* +'action'+: The action to execute, e.g. MoveToNextChar.
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
[options="header",width="75%",cols="25%,75%"]
|
[options="header",width="75%",cols="25%,75%"]
|
||||||
|==============
|
|==============
|
||||||
|Setting|Description
|
|Setting|Description
|
||||||
|
|<<ui-history-session-interval,history-session-interval>>|The maximum time in minutes between two history items for them to be considered being from the same session. Use -1 to disable separation.
|
||||||
|<<ui-zoom-levels,zoom-levels>>|The available zoom levels, separated by commas.
|
|<<ui-zoom-levels,zoom-levels>>|The available zoom levels, separated by commas.
|
||||||
|<<ui-default-zoom,default-zoom>>|The default zoom level.
|
|<<ui-default-zoom,default-zoom>>|The default zoom level.
|
||||||
|<<ui-downloads-position,downloads-position>>|Where to show the downloaded files.
|
|<<ui-downloads-position,downloads-position>>|Where to show the downloaded files.
|
||||||
@ -56,6 +57,7 @@
|
|||||||
|<<ui-modal-js-dialog,modal-js-dialog>>|Use standard JavaScript modal dialog for alert() and confirm()
|
|<<ui-modal-js-dialog,modal-js-dialog>>|Use standard JavaScript modal dialog for alert() and confirm()
|
||||||
|<<ui-hide-wayland-decoration,hide-wayland-decoration>>|Hide the window decoration when using wayland (requires restart)
|
|<<ui-hide-wayland-decoration,hide-wayland-decoration>>|Hide the window decoration when using wayland (requires restart)
|
||||||
|<<ui-keyhint-blacklist,keyhint-blacklist>>|Keychains that shouldn't be shown in the keyhint dialog
|
|<<ui-keyhint-blacklist,keyhint-blacklist>>|Keychains that shouldn't be shown in the keyhint dialog
|
||||||
|
|<<ui-keyhint-delay,keyhint-delay>>|Time from pressing a key to seeing the keyhint dialog (ms)
|
||||||
|<<ui-prompt-radius,prompt-radius>>|The rounding radius for the edges of prompts.
|
|<<ui-prompt-radius,prompt-radius>>|The rounding radius for the edges of prompts.
|
||||||
|<<ui-prompt-filebrowser,prompt-filebrowser>>|Show a filebrowser in upload/download prompts.
|
|<<ui-prompt-filebrowser,prompt-filebrowser>>|Show a filebrowser in upload/download prompts.
|
||||||
|==============
|
|==============
|
||||||
@ -124,6 +126,7 @@
|
|||||||
|<<tabs-close-mouse-button,close-mouse-button>>|On which mouse button to close tabs.
|
|<<tabs-close-mouse-button,close-mouse-button>>|On which mouse button to close tabs.
|
||||||
|<<tabs-position,position>>|The position of the tab bar.
|
|<<tabs-position,position>>|The position of the tab bar.
|
||||||
|<<tabs-show-favicons,show-favicons>>|Whether to show favicons in the tab bar.
|
|<<tabs-show-favicons,show-favicons>>|Whether to show favicons in the tab bar.
|
||||||
|
|<<tabs-favicon-scale,favicon-scale>>|Scale for favicons in the tab bar. The tab size is unchanged, so big favicons also require extra `tabs->padding`.
|
||||||
|<<tabs-width,width>>|The width of the tab bar if it's vertical, in px or as percentage of the window.
|
|<<tabs-width,width>>|The width of the tab bar if it's vertical, in px or as percentage of the window.
|
||||||
|<<tabs-indicator-width,indicator-width>>|Width of the progress indicator (0 to disable).
|
|<<tabs-indicator-width,indicator-width>>|Width of the progress indicator (0 to disable).
|
||||||
|<<tabs-tabs-are-windows,tabs-are-windows>>|Whether to open windows instead of tabs.
|
|<<tabs-tabs-are-windows,tabs-are-windows>>|Whether to open windows instead of tabs.
|
||||||
@ -172,7 +175,7 @@
|
|||||||
|<<content-local-content-can-access-remote-urls,local-content-can-access-remote-urls>>|Whether locally loaded documents are allowed to access remote urls.
|
|<<content-local-content-can-access-remote-urls,local-content-can-access-remote-urls>>|Whether locally loaded documents are allowed to access remote urls.
|
||||||
|<<content-local-content-can-access-file-urls,local-content-can-access-file-urls>>|Whether locally loaded documents are allowed to access other local urls.
|
|<<content-local-content-can-access-file-urls,local-content-can-access-file-urls>>|Whether locally loaded documents are allowed to access other local urls.
|
||||||
|<<content-cookies-accept,cookies-accept>>|Control which cookies to accept.
|
|<<content-cookies-accept,cookies-accept>>|Control which cookies to accept.
|
||||||
|<<content-cookies-store,cookies-store>>|Whether to store cookies. Note this option needs a restart with QtWebEngine.
|
|<<content-cookies-store,cookies-store>>|Whether to store cookies. Note this option needs a restart with QtWebEngine on Qt < 5.9.
|
||||||
|<<content-host-block-lists,host-block-lists>>|List of URLs of lists which contain hosts to block.
|
|<<content-host-block-lists,host-block-lists>>|List of URLs of lists which contain hosts to block.
|
||||||
|<<content-host-blocking-enabled,host-blocking-enabled>>|Whether host blocking is enabled.
|
|<<content-host-blocking-enabled,host-blocking-enabled>>|Whether host blocking is enabled.
|
||||||
|<<content-host-blocking-whitelist,host-blocking-whitelist>>|List of domains that should always be loaded, despite being ad-blocked.
|
|<<content-host-blocking-whitelist,host-blocking-whitelist>>|List of domains that should always be loaded, despite being ad-blocked.
|
||||||
@ -536,6 +539,12 @@ Default: +pass:[path,query]+
|
|||||||
== ui
|
== ui
|
||||||
General options related to the user interface.
|
General options related to the user interface.
|
||||||
|
|
||||||
|
[[ui-history-session-interval]]
|
||||||
|
=== history-session-interval
|
||||||
|
The maximum time in minutes between two history items for them to be considered being from the same session. Use -1 to disable separation.
|
||||||
|
|
||||||
|
Default: +pass:[30]+
|
||||||
|
|
||||||
[[ui-zoom-levels]]
|
[[ui-zoom-levels]]
|
||||||
=== zoom-levels
|
=== zoom-levels
|
||||||
The available zoom levels, separated by commas.
|
The available zoom levels, separated by commas.
|
||||||
@ -573,6 +582,7 @@ Default: +pass:[bottom]+
|
|||||||
[[ui-message-timeout]]
|
[[ui-message-timeout]]
|
||||||
=== message-timeout
|
=== message-timeout
|
||||||
Time (in ms) to show messages in the statusbar for.
|
Time (in ms) to show messages in the statusbar for.
|
||||||
|
Set to 0 to never clear messages.
|
||||||
|
|
||||||
Default: +pass:[2000]+
|
Default: +pass:[2000]+
|
||||||
|
|
||||||
@ -732,6 +742,12 @@ Globs are supported, so ';*' will blacklist all keychainsstarting with ';'. Use
|
|||||||
|
|
||||||
Default: empty
|
Default: empty
|
||||||
|
|
||||||
|
[[ui-keyhint-delay]]
|
||||||
|
=== keyhint-delay
|
||||||
|
Time from pressing a key to seeing the keyhint dialog (ms)
|
||||||
|
|
||||||
|
Default: +pass:[500]+
|
||||||
|
|
||||||
[[ui-prompt-radius]]
|
[[ui-prompt-radius]]
|
||||||
=== prompt-radius
|
=== prompt-radius
|
||||||
The rounding radius for the edges of prompts.
|
The rounding radius for the edges of prompts.
|
||||||
@ -1191,6 +1207,12 @@ Valid values:
|
|||||||
|
|
||||||
Default: +pass:[true]+
|
Default: +pass:[true]+
|
||||||
|
|
||||||
|
[[tabs-favicon-scale]]
|
||||||
|
=== favicon-scale
|
||||||
|
Scale for favicons in the tab bar. The tab size is unchanged, so big favicons also require extra `tabs->padding`.
|
||||||
|
|
||||||
|
Default: +pass:[1.0]+
|
||||||
|
|
||||||
[[tabs-width]]
|
[[tabs-width]]
|
||||||
=== width
|
=== width
|
||||||
The width of the tab bar if it's vertical, in px or as percentage of the window.
|
The width of the tab bar if it's vertical, in px or as percentage of the window.
|
||||||
@ -1594,7 +1616,7 @@ This setting is only available with the QtWebKit backend.
|
|||||||
|
|
||||||
[[content-cookies-store]]
|
[[content-cookies-store]]
|
||||||
=== cookies-store
|
=== cookies-store
|
||||||
Whether to store cookies. Note this option needs a restart with QtWebEngine.
|
Whether to store cookies. Note this option needs a restart with QtWebEngine on Qt < 5.9.
|
||||||
|
|
||||||
Valid values:
|
Valid values:
|
||||||
|
|
||||||
@ -2252,7 +2274,7 @@ Fonts used for the UI, with optional style/weight/size.
|
|||||||
=== _monospace
|
=== _monospace
|
||||||
Default monospace fonts.
|
Default monospace fonts.
|
||||||
|
|
||||||
Default: +pass:[Terminus, Monospace, "DejaVu Sans Mono", Monaco, "Bitstream Vera Sans Mono", "Andale Mono", "Courier New", Courier, "Liberation Mono", monospace, Fixed, Consolas, Terminal]+
|
Default: +pass:[xos4 Terminus, Terminus, Monospace, "DejaVu Sans Mono", Monaco, "Bitstream Vera Sans Mono", "Andale Mono", "Courier New", Courier, "Liberation Mono", monospace, Fixed, Consolas, Terminal]+
|
||||||
|
|
||||||
[[fonts-completion]]
|
[[fonts-completion]]
|
||||||
=== completion
|
=== completion
|
||||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 58 KiB |
BIN
doc/img/main.png
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 46 KiB |
@ -93,12 +93,6 @@ show it.
|
|||||||
*--nowindow*::
|
*--nowindow*::
|
||||||
Don't show the main window.
|
Don't show the main window.
|
||||||
|
|
||||||
*--debug-exit*::
|
|
||||||
Turn on debugging of late exit.
|
|
||||||
|
|
||||||
*--pdb-postmortem*::
|
|
||||||
Drop into pdb on exceptions.
|
|
||||||
|
|
||||||
*--temp-basedir*::
|
*--temp-basedir*::
|
||||||
Use a temporary basedir.
|
Use a temporary basedir.
|
||||||
|
|
||||||
@ -110,6 +104,9 @@ show it.
|
|||||||
|
|
||||||
*--qt-flag* 'QT_FLAG'::
|
*--qt-flag* 'QT_FLAG'::
|
||||||
Pass an argument to Qt as flag.
|
Pass an argument to Qt as flag.
|
||||||
|
|
||||||
|
*--debug-flag* 'DEBUG_FLAGS'::
|
||||||
|
Pass name of debugging feature to be turned on.
|
||||||
// QUTE_OPTIONS_END
|
// QUTE_OPTIONS_END
|
||||||
|
|
||||||
== FILES
|
== FILES
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||||
|
|
||||||
codecov==2.0.5
|
codecov==2.0.9
|
||||||
coverage==4.3.4
|
coverage==4.4
|
||||||
requests==2.13.0
|
requests==2.14.1
|
||||||
|
@ -4,7 +4,7 @@ flake8==2.6.2 # rq.filter: < 3.0.0
|
|||||||
flake8-copyright==0.2.0
|
flake8-copyright==0.2.0
|
||||||
flake8-debugger==1.4.0 # rq.filter: != 2.0.0
|
flake8-debugger==1.4.0 # rq.filter: != 2.0.0
|
||||||
flake8-deprecated==1.1
|
flake8-deprecated==1.1
|
||||||
flake8-docstrings==1.0.3
|
flake8-docstrings==1.0.3 # rq.filter: < 1.1.0
|
||||||
flake8-future-import==0.4.3
|
flake8-future-import==0.4.3
|
||||||
flake8-mock==0.3
|
flake8-mock==0.3
|
||||||
flake8-pep3101==1.0
|
flake8-pep3101==1.0
|
||||||
@ -12,9 +12,9 @@ flake8-polyfill==1.0.1
|
|||||||
flake8-putty==0.4.0
|
flake8-putty==0.4.0
|
||||||
flake8-string-format==0.2.3
|
flake8-string-format==0.2.3
|
||||||
flake8-tidy-imports==1.0.6
|
flake8-tidy-imports==1.0.6
|
||||||
flake8-tuple==0.2.12
|
flake8-tuple==0.2.13
|
||||||
mccabe==0.6.1
|
mccabe==0.6.1
|
||||||
pep8-naming==0.4.1
|
pep8-naming==0.4.1
|
||||||
pycodestyle==2.3.1
|
pycodestyle==2.3.1
|
||||||
pydocstyle==1.1.1
|
pydocstyle==1.1.1 # rq.filter: < 2.0.0
|
||||||
pyflakes==1.5.0
|
pyflakes==1.5.0
|
||||||
|
@ -2,7 +2,7 @@ flake8<3.0.0
|
|||||||
flake8-copyright
|
flake8-copyright
|
||||||
flake8-debugger!=2.0.0
|
flake8-debugger!=2.0.0
|
||||||
flake8-deprecated
|
flake8-deprecated
|
||||||
flake8-docstrings
|
flake8-docstrings<1.1.0
|
||||||
flake8-future-import
|
flake8-future-import
|
||||||
flake8-mock
|
flake8-mock
|
||||||
flake8-pep3101
|
flake8-pep3101
|
||||||
@ -11,7 +11,7 @@ flake8-string-format
|
|||||||
flake8-tidy-imports
|
flake8-tidy-imports
|
||||||
flake8-tuple
|
flake8-tuple
|
||||||
pep8-naming
|
pep8-naming
|
||||||
pydocstyle
|
pydocstyle<2.0.0
|
||||||
pyflakes
|
pyflakes
|
||||||
|
|
||||||
# Pinned to 2.0.0 otherwise
|
# Pinned to 2.0.0 otherwise
|
||||||
@ -21,6 +21,8 @@ mccabe==0.6.1
|
|||||||
|
|
||||||
# Waiting until flake8-putty updated
|
# Waiting until flake8-putty updated
|
||||||
#@ filter: flake8 < 3.0.0
|
#@ filter: flake8 < 3.0.0
|
||||||
|
#@ filter: pydocstyle < 2.0.0
|
||||||
|
#@ filter: flake8-docstrings < 1.1.0
|
||||||
|
|
||||||
# https://github.com/JBKahn/flake8-debugger/issues/5
|
# https://github.com/JBKahn/flake8-debugger/issues/5
|
||||||
#@ filter: flake8-debugger != 2.0.0
|
#@ filter: flake8-debugger != 2.0.0
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
appdirs==1.4.3
|
appdirs==1.4.3
|
||||||
packaging==16.8
|
packaging==16.8
|
||||||
pyparsing==2.2.0
|
pyparsing==2.2.0
|
||||||
setuptools==34.3.2
|
setuptools==35.0.2
|
||||||
six==1.10.0
|
six==1.10.0
|
||||||
wheel==0.29.0
|
wheel==0.29.0
|
||||||
|
@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
-e git+https://github.com/PyCQA/astroid.git#egg=astroid
|
-e git+https://github.com/PyCQA/astroid.git#egg=astroid
|
||||||
editdistance==0.3.1
|
editdistance==0.3.1
|
||||||
|
github3.py==0.9.6
|
||||||
isort==4.2.5
|
isort==4.2.5
|
||||||
lazy-object-proxy==1.2.2
|
lazy-object-proxy==1.3.1
|
||||||
mccabe==0.6.1
|
mccabe==0.6.1
|
||||||
-e git+https://github.com/PyCQA/pylint.git#egg=pylint
|
-e git+https://github.com/PyCQA/pylint.git#egg=pylint
|
||||||
./scripts/dev/pylint_checkers
|
./scripts/dev/pylint_checkers
|
||||||
requests==2.13.0
|
requests==2.14.1
|
||||||
|
uritemplate==3.0.0
|
||||||
|
uritemplate.py==3.0.2
|
||||||
wrapt==1.10.10
|
wrapt==1.10.10
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
-e git+https://github.com/PyCQA/pylint.git#egg=pylint
|
-e git+https://github.com/PyCQA/pylint.git#egg=pylint
|
||||||
./scripts/dev/pylint_checkers
|
./scripts/dev/pylint_checkers
|
||||||
requests
|
requests
|
||||||
|
github3.py
|
||||||
|
|
||||||
# remove @commit-id for scm installs
|
# remove @commit-id for scm installs
|
||||||
#@ replace: @.*# #
|
#@ replace: @.*# #
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||||
|
|
||||||
astroid==1.4.9
|
astroid==1.5.2
|
||||||
github3.py==0.9.6
|
github3.py==0.9.6
|
||||||
isort==4.2.5
|
isort==4.2.5
|
||||||
lazy-object-proxy==1.2.2
|
lazy-object-proxy==1.3.1
|
||||||
mccabe==0.6.1
|
mccabe==0.6.1
|
||||||
pylint==1.6.5
|
pylint==1.7.1
|
||||||
./scripts/dev/pylint_checkers
|
./scripts/dev/pylint_checkers
|
||||||
requests==2.13.0
|
requests==2.14.1
|
||||||
uritemplate==3.0.0
|
uritemplate==3.0.0
|
||||||
uritemplate.py==3.0.2
|
uritemplate.py==3.0.2
|
||||||
wrapt==1.10.10
|
wrapt==1.10.10
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||||
|
|
||||||
PyQt5==5.8.1.1
|
PyQt5==5.8.2
|
||||||
sip==4.19.1
|
sip==4.19.2
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||||
|
|
||||||
beautifulsoup4==4.5.3
|
beautifulsoup4==4.6.0
|
||||||
cheroot==5.3.0
|
cheroot==5.5.0
|
||||||
click==6.7
|
click==6.7
|
||||||
coverage==4.3.4
|
coverage==4.4
|
||||||
decorator==4.0.11
|
decorator==4.0.11
|
||||||
EasyProcess==0.2.3
|
EasyProcess==0.2.3
|
||||||
Flask==0.12
|
Flask==0.12.1
|
||||||
glob2==0.5
|
glob2==0.5
|
||||||
httpbin==0.5.0
|
httpbin==0.5.0
|
||||||
hypothesis==3.6.1
|
hypothesis==3.8.3
|
||||||
itsdangerous==0.24
|
itsdangerous==0.24
|
||||||
# Jinja2==2.9.5
|
# Jinja2==2.9.5
|
||||||
Mako==1.0.6
|
Mako==1.0.6
|
||||||
@ -18,13 +18,13 @@ parse==1.8.0
|
|||||||
parse-type==0.3.4
|
parse-type==0.3.4
|
||||||
py==1.4.33
|
py==1.4.33
|
||||||
pytest==3.0.7
|
pytest==3.0.7
|
||||||
pytest-bdd==2.18.1
|
pytest-bdd==2.18.2
|
||||||
pytest-benchmark==3.0.0
|
pytest-benchmark==3.0.0
|
||||||
pytest-catchlog==1.2.2
|
pytest-catchlog==1.2.2
|
||||||
pytest-cov==2.4.0
|
pytest-cov==2.5.0
|
||||||
pytest-faulthandler==1.3.1
|
pytest-faulthandler==1.3.1
|
||||||
pytest-instafail==0.3.0
|
pytest-instafail==0.3.0
|
||||||
pytest-mock==1.5.0
|
pytest-mock==1.6.0
|
||||||
pytest-qt==2.1.0
|
pytest-qt==2.1.0
|
||||||
pytest-repeat==0.4.1
|
pytest-repeat==0.4.1
|
||||||
pytest-rerunfailures==2.1.0
|
pytest-rerunfailures==2.1.0
|
||||||
@ -32,5 +32,5 @@ pytest-travis-fold==1.2.0
|
|||||||
pytest-warnings==0.2.0
|
pytest-warnings==0.2.0
|
||||||
pytest-xvfb==1.0.0
|
pytest-xvfb==1.0.0
|
||||||
PyVirtualDisplay==0.2.1
|
PyVirtualDisplay==0.2.1
|
||||||
vulture==0.13
|
vulture==0.14
|
||||||
Werkzeug==0.12.1
|
Werkzeug==0.12.1
|
||||||
|
@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
pluggy==0.4.0
|
pluggy==0.4.0
|
||||||
py==1.4.33
|
py==1.4.33
|
||||||
tox==2.6.0
|
tox==2.7.0
|
||||||
virtualenv==15.1.0
|
virtualenv==15.1.0
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||||
|
|
||||||
vulture==0.13
|
vulture==0.14
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Copyright 2015 Zach-Button <zachrey.button@gmail.com>
|
# Copyright 2015 Zach-Button <zachrey.button@gmail.com>
|
||||||
|
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Copyright 2015 jnphilipp <me@jnphilipp.org>
|
# Copyright 2015 jnphilipp <me@jnphilipp.org>
|
||||||
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -9,7 +9,7 @@ directly ask me via IRC (nickname thorsten\`) in #qutebrowser on freenode.
|
|||||||
|
|
||||||
$blink!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$reset
|
$blink!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$reset
|
||||||
WARNING: the passwords are stored in qutebrowser's
|
WARNING: the passwords are stored in qutebrowser's
|
||||||
debug log reachable via the url qute:log
|
debug log reachable via the url qute://log
|
||||||
$blink!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$reset
|
$blink!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$reset
|
||||||
|
|
||||||
Usage: run as a userscript form qutebrowser, e.g.:
|
Usage: run as a userscript form qutebrowser, e.g.:
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Copyright 2015 Zach-Button <zachrey.button@gmail.com>
|
# Copyright 2015 Zach-Button <zachrey.button@gmail.com>
|
||||||
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -24,11 +24,12 @@ markers =
|
|||||||
js_prompt: Tests needing to display a javascript prompt
|
js_prompt: Tests needing to display a javascript prompt
|
||||||
this: Used to mark tests during development
|
this: Used to mark tests during development
|
||||||
no_invalid_lines: Don't fail on unparseable lines in end2end tests
|
no_invalid_lines: Don't fail on unparseable lines in end2end tests
|
||||||
|
issue2478: Tests which are broken on Windows with QtWebEngine, https://github.com/qutebrowser/qutebrowser/issues/2478
|
||||||
qt_log_level_fail = WARNING
|
qt_log_level_fail = WARNING
|
||||||
qt_log_ignore =
|
qt_log_ignore =
|
||||||
^SpellCheck: .*
|
^SpellCheck: .*
|
||||||
^SetProcessDpiAwareness failed: .*
|
^SetProcessDpiAwareness failed: .*
|
||||||
^QWindowsWindow::setGeometryDp: Unable to set geometry .*
|
^QWindowsWindow::setGeometry(Dp)?: Unable to set geometry .*
|
||||||
^QProcess: Destroyed while process .* is still running\.
|
^QProcess: Destroyed while process .* is still running\.
|
||||||
^"Method "GetAll" with signature "s" on interface "org\.freedesktop\.DBus\.Properties" doesn't exist
|
^"Method "GetAll" with signature "s" on interface "org\.freedesktop\.DBus\.Properties" doesn't exist
|
||||||
^"Method \\"GetAll\\" with signature \\"s\\" on interface \\"org\.freedesktop\.DBus\.Properties\\" doesn't exist\\n"
|
^"Method \\"GetAll\\" with signature \\"s\\" on interface \\"org\.freedesktop\.DBus\.Properties\\" doesn't exist\\n"
|
||||||
@ -51,4 +52,5 @@ qt_log_ignore =
|
|||||||
^Image of format '' blocked because it is not considered safe. If you are sure it is safe to do so, you can white-list the format by setting the environment variable QTWEBKIT_IMAGEFORMAT_WHITELIST=
|
^Image of format '' blocked because it is not considered safe. If you are sure it is safe to do so, you can white-list the format by setting the environment variable QTWEBKIT_IMAGEFORMAT_WHITELIST=
|
||||||
^QPainter::end: Painter ended with \d+ saved states
|
^QPainter::end: Painter ended with \d+ saved states
|
||||||
^QSslSocket: cannot resolve SSLv[23]_(client|server)_method
|
^QSslSocket: cannot resolve SSLv[23]_(client|server)_method
|
||||||
|
^QQuickWidget::invalidateRenderControl could not make context current
|
||||||
xfail_strict = true
|
xfail_strict = true
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -22,7 +22,7 @@
|
|||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
__author__ = "Florian Bruhin"
|
__author__ = "Florian Bruhin"
|
||||||
__copyright__ = "Copyright 2014-2016 Florian Bruhin (The Compiler)"
|
__copyright__ = "Copyright 2014-2017 Florian Bruhin (The Compiler)"
|
||||||
__license__ = "GPL"
|
__license__ = "GPL"
|
||||||
__maintainer__ = __author__
|
__maintainer__ = __author__
|
||||||
__email__ = "mail@qutebrowser.org"
|
__email__ = "mail@qutebrowser.org"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -170,11 +170,14 @@ def _init_icon():
|
|||||||
for size in [16, 24, 32, 48, 64, 96, 128, 256, 512]:
|
for size in [16, 24, 32, 48, 64, 96, 128, 256, 512]:
|
||||||
filename = ':/icons/qutebrowser-{}x{}.png'.format(size, size)
|
filename = ':/icons/qutebrowser-{}x{}.png'.format(size, size)
|
||||||
pixmap = QPixmap(filename)
|
pixmap = QPixmap(filename)
|
||||||
qtutils.ensure_not_null(pixmap)
|
if pixmap.isNull():
|
||||||
|
log.init.warning("Failed to load {}".format(filename))
|
||||||
|
else:
|
||||||
fallback_icon.addPixmap(pixmap)
|
fallback_icon.addPixmap(pixmap)
|
||||||
qtutils.ensure_not_null(fallback_icon)
|
|
||||||
icon = QIcon.fromTheme('qutebrowser', fallback_icon)
|
icon = QIcon.fromTheme('qutebrowser', fallback_icon)
|
||||||
qtutils.ensure_not_null(icon)
|
if icon.isNull():
|
||||||
|
log.init.warning("Failed to load icon")
|
||||||
|
else:
|
||||||
qApp.setWindowIcon(icon)
|
qApp.setWindowIcon(icon)
|
||||||
|
|
||||||
|
|
||||||
@ -301,7 +304,7 @@ def _open_startpage(win_id=None):
|
|||||||
window_ids = [win_id]
|
window_ids = [win_id]
|
||||||
else:
|
else:
|
||||||
window_ids = objreg.window_registry
|
window_ids = objreg.window_registry
|
||||||
for cur_win_id in window_ids:
|
for cur_win_id in list(window_ids): # Copying as the dict could change
|
||||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||||
window=cur_win_id)
|
window=cur_win_id)
|
||||||
if tabbed_browser.count() == 0:
|
if tabbed_browser.count() == 0:
|
||||||
@ -340,7 +343,8 @@ def _open_quickstart(args):
|
|||||||
|
|
||||||
def _save_version():
|
def _save_version():
|
||||||
"""Save the current version to the state config."""
|
"""Save the current version to the state config."""
|
||||||
state_config = objreg.get('state-config')
|
state_config = objreg.get('state-config', None)
|
||||||
|
if state_config is not None:
|
||||||
state_config['general']['version'] = qutebrowser.__version__
|
state_config['general']['version'] = qutebrowser.__version__
|
||||||
|
|
||||||
|
|
||||||
@ -647,8 +651,8 @@ class Quitter:
|
|||||||
self._shutting_down = True
|
self._shutting_down = True
|
||||||
log.destroy.debug("Shutting down with status {}, session {}...".format(
|
log.destroy.debug("Shutting down with status {}, session {}...".format(
|
||||||
status, session))
|
status, session))
|
||||||
|
session_manager = objreg.get('session-manager', None)
|
||||||
session_manager = objreg.get('session-manager')
|
if session_manager is not None:
|
||||||
if session is not None:
|
if session is not None:
|
||||||
session_manager.save(session, last_window=last_window,
|
session_manager.save(session, last_window=last_window,
|
||||||
load_next_time=True)
|
load_next_time=True)
|
||||||
@ -671,7 +675,7 @@ class Quitter:
|
|||||||
# event loop, so we can shut down immediately.
|
# event loop, so we can shut down immediately.
|
||||||
self._shutdown(status, restart=restart)
|
self._shutdown(status, restart=restart)
|
||||||
|
|
||||||
def _shutdown(self, status, restart):
|
def _shutdown(self, status, restart): # noqa
|
||||||
"""Second stage of shutdown."""
|
"""Second stage of shutdown."""
|
||||||
log.destroy.debug("Stage 2 of shutting down...")
|
log.destroy.debug("Stage 2 of shutting down...")
|
||||||
if qApp is None:
|
if qApp is None:
|
||||||
@ -680,7 +684,9 @@ class Quitter:
|
|||||||
# Remove eventfilter
|
# Remove eventfilter
|
||||||
try:
|
try:
|
||||||
log.destroy.debug("Removing eventfilter...")
|
log.destroy.debug("Removing eventfilter...")
|
||||||
qApp.removeEventFilter(objreg.get('event-filter'))
|
event_filter = objreg.get('event-filter', None)
|
||||||
|
if event_filter is not None:
|
||||||
|
qApp.removeEventFilter(event_filter)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
# Close all windows
|
# Close all windows
|
||||||
@ -722,7 +728,9 @@ class Quitter:
|
|||||||
# Now we can hopefully quit without segfaults
|
# Now we can hopefully quit without segfaults
|
||||||
log.destroy.debug("Deferring QApplication::exit...")
|
log.destroy.debug("Deferring QApplication::exit...")
|
||||||
objreg.get('signal-handler').deactivate()
|
objreg.get('signal-handler').deactivate()
|
||||||
objreg.get('session-manager').delete_autosave()
|
session_manager = objreg.get('session-manager', None)
|
||||||
|
if session_manager is not None:
|
||||||
|
session_manager.delete_autosave()
|
||||||
# We use a singleshot timer to exit here to minimize the likelihood of
|
# We use a singleshot timer to exit here to minimize the likelihood of
|
||||||
# segfaults.
|
# segfaults.
|
||||||
QTimer.singleShot(0, functools.partial(qApp.exit, status))
|
QTimer.singleShot(0, functools.partial(qApp.exit, status))
|
||||||
@ -784,7 +792,7 @@ class Application(QApplication):
|
|||||||
def exit(self, status):
|
def exit(self, status):
|
||||||
"""Extend QApplication::exit to log the event."""
|
"""Extend QApplication::exit to log the event."""
|
||||||
log.destroy.debug("Now calling QApplication::exit.")
|
log.destroy.debug("Now calling QApplication::exit.")
|
||||||
if self._args.debug_exit:
|
if 'debug-exit' in self._args.debug_flags:
|
||||||
if hunter is None:
|
if hunter is None:
|
||||||
print("Not logging late shutdown because hunter could not be "
|
print("Not logging late shutdown because hunter could not be "
|
||||||
"imported!", file=sys.stderr)
|
"imported!", file=sys.stderr)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QUrl, QObject, QSizeF
|
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QUrl, QObject, QSizeF, Qt
|
||||||
from PyQt5.QtGui import QIcon
|
from PyQt5.QtGui import QIcon
|
||||||
from PyQt5.QtWidgets import QWidget, QApplication
|
from PyQt5.QtWidgets import QWidget, QApplication
|
||||||
|
|
||||||
@ -107,7 +107,15 @@ class TabData:
|
|||||||
|
|
||||||
class AbstractAction:
|
class AbstractAction:
|
||||||
|
|
||||||
"""Attribute of AbstractTab for Qt WebActions."""
|
"""Attribute of AbstractTab for Qt WebActions.
|
||||||
|
|
||||||
|
Class attributes (overridden by subclasses):
|
||||||
|
action_class: The class actions are defined on (QWeb{Engine,}Page)
|
||||||
|
action_base: The type of the actions (QWeb{Engine,}Page.WebAction)
|
||||||
|
"""
|
||||||
|
|
||||||
|
action_class = None
|
||||||
|
action_base = None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._widget = None
|
self._widget = None
|
||||||
@ -120,6 +128,13 @@ class AbstractAction:
|
|||||||
"""Save the current page."""
|
"""Save the current page."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def run_string(self, name):
|
||||||
|
"""Run a webaction based on its name."""
|
||||||
|
member = getattr(self.action_class, name, None)
|
||||||
|
if not isinstance(member, self.action_base):
|
||||||
|
raise WebTabError("{} is not a valid web action!".format(name))
|
||||||
|
self._widget.triggerPageAction(member)
|
||||||
|
|
||||||
|
|
||||||
class AbstractPrinting:
|
class AbstractPrinting:
|
||||||
|
|
||||||
@ -157,6 +172,8 @@ class AbstractSearch(QObject):
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
text: The last thing this view was searched for.
|
text: The last thing this view was searched for.
|
||||||
|
search_displayed: Whether we're currently displaying search results in
|
||||||
|
this view.
|
||||||
_flags: The flags of the last search (needs to be set by subclasses).
|
_flags: The flags of the last search (needs to be set by subclasses).
|
||||||
_widget: The underlying WebView widget.
|
_widget: The underlying WebView widget.
|
||||||
"""
|
"""
|
||||||
@ -165,6 +182,7 @@ class AbstractSearch(QObject):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._widget = None
|
self._widget = None
|
||||||
self.text = None
|
self.text = None
|
||||||
|
self.search_displayed = False
|
||||||
|
|
||||||
def search(self, text, *, ignore_case=False, reverse=False,
|
def search(self, text, *, ignore_case=False, reverse=False,
|
||||||
result_cb=None):
|
result_cb=None):
|
||||||
@ -742,6 +760,10 @@ class AbstractTab(QWidget):
|
|||||||
def clear_ssl_errors(self):
|
def clear_ssl_errors(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def key_press(self, key, modifier=Qt.NoModifier):
|
||||||
|
"""Send a fake key event to this tab."""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
def dump_async(self, callback, *, plain=False):
|
def dump_async(self, callback, *, plain=False):
|
||||||
"""Dump the current page to a file ascync.
|
"""Dump the current page to a file ascync.
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -28,14 +28,6 @@ from PyQt5.QtWidgets import QApplication, QTabBar
|
|||||||
from PyQt5.QtCore import Qt, QUrl, QEvent, QUrlQuery
|
from PyQt5.QtCore import Qt, QUrl, QEvent, QUrlQuery
|
||||||
from PyQt5.QtGui import QKeyEvent
|
from PyQt5.QtGui import QKeyEvent
|
||||||
from PyQt5.QtPrintSupport import QPrintDialog, QPrintPreviewDialog
|
from PyQt5.QtPrintSupport import QPrintDialog, QPrintPreviewDialog
|
||||||
try:
|
|
||||||
from PyQt5.QtWebKitWidgets import QWebPage
|
|
||||||
except ImportError:
|
|
||||||
QWebPage = None
|
|
||||||
try:
|
|
||||||
from PyQt5.QtWebEngineWidgets import QWebEnginePage
|
|
||||||
except ImportError:
|
|
||||||
QWebEnginePage = None
|
|
||||||
import pygments
|
import pygments
|
||||||
import pygments.lexers
|
import pygments.lexers
|
||||||
import pygments.formatters
|
import pygments.formatters
|
||||||
@ -289,7 +281,7 @@ class CommandDispatcher:
|
|||||||
@cmdutils.argument('url', completion=usertypes.Completion.url)
|
@cmdutils.argument('url', completion=usertypes.Completion.url)
|
||||||
@cmdutils.argument('count', count=True)
|
@cmdutils.argument('count', count=True)
|
||||||
def openurl(self, url=None, implicit=False,
|
def openurl(self, url=None, implicit=False,
|
||||||
bg=False, tab=False, window=False, count=None):
|
bg=False, tab=False, window=False, count=None, secure=False):
|
||||||
"""Open a URL in the current/[count]th tab.
|
"""Open a URL in the current/[count]th tab.
|
||||||
|
|
||||||
If the URL contains newlines, each line gets opened in its own tab.
|
If the URL contains newlines, each line gets opened in its own tab.
|
||||||
@ -302,6 +294,7 @@ class CommandDispatcher:
|
|||||||
implicit: If opening a new tab, treat the tab as implicit (like
|
implicit: If opening a new tab, treat the tab as implicit (like
|
||||||
clicking on a link).
|
clicking on a link).
|
||||||
count: The tab index to open the URL in, or None.
|
count: The tab index to open the URL in, or None.
|
||||||
|
secure: Force HTTPS.
|
||||||
"""
|
"""
|
||||||
if url is None:
|
if url is None:
|
||||||
urls = [config.get('general', 'default-page')]
|
urls = [config.get('general', 'default-page')]
|
||||||
@ -309,6 +302,8 @@ class CommandDispatcher:
|
|||||||
urls = self._parse_url_input(url)
|
urls = self._parse_url_input(url)
|
||||||
|
|
||||||
for i, cur_url in enumerate(urls):
|
for i, cur_url in enumerate(urls):
|
||||||
|
if secure:
|
||||||
|
cur_url.setScheme('https')
|
||||||
if not window and i > 0:
|
if not window and i > 0:
|
||||||
tab = False
|
tab = False
|
||||||
bg = True
|
bg = True
|
||||||
@ -1285,7 +1280,7 @@ class CommandDispatcher:
|
|||||||
except urlmarks.Error as e:
|
except urlmarks.Error as e:
|
||||||
raise cmdexc.CommandError(str(e))
|
raise cmdexc.CommandError(str(e))
|
||||||
else:
|
else:
|
||||||
msg = "Bookmarked {}!" if was_added else "Removed bookmark {}!"
|
msg = "Bookmarked {}" if was_added else "Removed bookmark {}"
|
||||||
message.info(msg.format(url.toDisplayString()))
|
message.info(msg.format(url.toDisplayString()))
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window',
|
@cmdutils.register(instance='command-dispatcher', scope='window',
|
||||||
@ -1389,6 +1384,9 @@ class CommandDispatcher:
|
|||||||
scope='window', window=self._win_id)
|
scope='window', window=self._win_id)
|
||||||
target = None
|
target = None
|
||||||
if dest is not None:
|
if dest is not None:
|
||||||
|
dest = downloads.transform_path(dest)
|
||||||
|
if dest is None:
|
||||||
|
raise cmdexc.CommandError("Invalid target filename")
|
||||||
target = downloads.FileDownloadTarget(dest)
|
target = downloads.FileDownloadTarget(dest)
|
||||||
|
|
||||||
tab = self._current_widget()
|
tab = self._current_widget()
|
||||||
@ -1554,6 +1552,7 @@ class CommandDispatcher:
|
|||||||
if text is None:
|
if text is None:
|
||||||
message.error("Could not get text from the focused element.")
|
message.error("Could not get text from the focused element.")
|
||||||
return
|
return
|
||||||
|
assert isinstance(text, str), text
|
||||||
|
|
||||||
ed = editor.ExternalEditor(self._tabbed_browser)
|
ed = editor.ExternalEditor(self._tabbed_browser)
|
||||||
ed.editing_finished.connect(functools.partial(
|
ed.editing_finished.connect(functools.partial(
|
||||||
@ -1591,10 +1590,7 @@ class CommandDispatcher:
|
|||||||
backend=usertypes.Backend.QtWebKit)
|
backend=usertypes.Backend.QtWebKit)
|
||||||
def paste_primary(self):
|
def paste_primary(self):
|
||||||
"""Paste the primary selection at cursor position."""
|
"""Paste the primary selection at cursor position."""
|
||||||
try:
|
self.insert_text(utils.get_clipboard(selection=True, fallback=True))
|
||||||
self.insert_text(utils.get_clipboard(selection=True))
|
|
||||||
except utils.SelectionUnsupportedError:
|
|
||||||
self.insert_text(utils.get_clipboard())
|
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', maxsplit=0,
|
@cmdutils.register(instance='command-dispatcher', maxsplit=0,
|
||||||
scope='window')
|
scope='window')
|
||||||
@ -1705,21 +1701,22 @@ class CommandDispatcher:
|
|||||||
tab = self._current_widget()
|
tab = self._current_widget()
|
||||||
tab.search.clear()
|
tab.search.clear()
|
||||||
|
|
||||||
|
if not text:
|
||||||
|
return
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
'ignore_case': config.get('general', 'ignore-case'),
|
'ignore_case': config.get('general', 'ignore-case'),
|
||||||
'reverse': reverse,
|
'reverse': reverse,
|
||||||
}
|
}
|
||||||
|
|
||||||
self._tabbed_browser.search_text = text
|
self._tabbed_browser.search_text = text
|
||||||
self._tabbed_browser.search_options = dict(options)
|
self._tabbed_browser.search_options = dict(options)
|
||||||
|
|
||||||
if text:
|
|
||||||
cb = functools.partial(self._search_cb, tab=tab,
|
cb = functools.partial(self._search_cb, tab=tab,
|
||||||
old_scroll_pos=tab.scroller.pos_px(),
|
old_scroll_pos=tab.scroller.pos_px(),
|
||||||
options=options, text=text, prev=False)
|
options=options, text=text, prev=False)
|
||||||
else:
|
|
||||||
cb = None
|
|
||||||
|
|
||||||
options['result_cb'] = cb
|
options['result_cb'] = cb
|
||||||
|
|
||||||
tab.search.search(text, **options)
|
tab.search.search(text, **options)
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', hide=True,
|
@cmdutils.register(instance='command-dispatcher', hide=True,
|
||||||
@ -1955,33 +1952,20 @@ class CommandDispatcher:
|
|||||||
def debug_webaction(self, action, count=1):
|
def debug_webaction(self, action, count=1):
|
||||||
"""Execute a webaction.
|
"""Execute a webaction.
|
||||||
|
|
||||||
See http://doc.qt.io/qt-5/qwebpage.html#WebAction-enum for the
|
Available actions:
|
||||||
available actions.
|
http://doc.qt.io/archives/qt-5.5/qwebpage.html#WebAction-enum (WebKit)
|
||||||
|
http://doc.qt.io/qt-5/qwebenginepage.html#WebAction-enum (WebEngine)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
action: The action to execute, e.g. MoveToNextChar.
|
action: The action to execute, e.g. MoveToNextChar.
|
||||||
count: How many times to repeat the action.
|
count: How many times to repeat the action.
|
||||||
"""
|
"""
|
||||||
tab = self._current_widget()
|
tab = self._current_widget()
|
||||||
|
|
||||||
if tab.backend == usertypes.Backend.QtWebKit:
|
|
||||||
assert QWebPage is not None
|
|
||||||
member = getattr(QWebPage, action, None)
|
|
||||||
base = QWebPage.WebAction
|
|
||||||
elif tab.backend == usertypes.Backend.QtWebEngine:
|
|
||||||
assert QWebEnginePage is not None
|
|
||||||
member = getattr(QWebEnginePage, action, None)
|
|
||||||
base = QWebEnginePage.WebAction
|
|
||||||
|
|
||||||
if not isinstance(member, base):
|
|
||||||
raise cmdexc.CommandError("{} is not a valid web action!".format(
|
|
||||||
action))
|
|
||||||
|
|
||||||
for _ in range(count):
|
for _ in range(count):
|
||||||
# This whole command is backend-specific anyways, so it makes no
|
try:
|
||||||
# sense to introduce some API for this.
|
tab.action.run_string(action)
|
||||||
# pylint: disable=protected-access
|
except browsertab.WebTabError as e:
|
||||||
tab._widget.triggerPageAction(member)
|
raise cmdexc.CommandError(str(e))
|
||||||
|
|
||||||
@cmdutils.register(instance='command-dispatcher', scope='window',
|
@cmdutils.register(instance='command-dispatcher', scope='window',
|
||||||
maxsplit=0, no_cmd_split=True)
|
maxsplit=0, no_cmd_split=True)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -19,11 +19,13 @@
|
|||||||
|
|
||||||
"""Shared QtWebKit/QtWebEngine code for downloads."""
|
"""Shared QtWebKit/QtWebEngine code for downloads."""
|
||||||
|
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import html
|
import html
|
||||||
import os.path
|
import os.path
|
||||||
import collections
|
import collections
|
||||||
import functools
|
import functools
|
||||||
|
import pathlib
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
import sip
|
import sip
|
||||||
@ -161,6 +163,25 @@ def get_filename_question(*, suggested_filename, url, parent=None):
|
|||||||
return q
|
return q
|
||||||
|
|
||||||
|
|
||||||
|
def transform_path(path):
|
||||||
|
r"""Do platform-specific transformations, like changing E: to E:\.
|
||||||
|
|
||||||
|
Returns None if the path is invalid on the current platform.
|
||||||
|
"""
|
||||||
|
if sys.platform != "win32":
|
||||||
|
return path
|
||||||
|
path = utils.expand_windows_drive(path)
|
||||||
|
# Drive dependent working directories are not supported, e.g.
|
||||||
|
# E:filename is invalid
|
||||||
|
if re.match(r'[A-Z]:[^\\]', path, re.IGNORECASE):
|
||||||
|
return None
|
||||||
|
# Paths like COM1, ...
|
||||||
|
# See https://github.com/qutebrowser/qutebrowser/issues/82
|
||||||
|
if pathlib.Path(path).is_reserved():
|
||||||
|
return None
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
class NoFilenameError(Exception):
|
class NoFilenameError(Exception):
|
||||||
|
|
||||||
"""Raised when we can't find out a filename in DownloadTarget."""
|
"""Raised when we can't find out a filename in DownloadTarget."""
|
||||||
@ -507,6 +528,14 @@ class AbstractDownloadItem(QObject):
|
|||||||
"""Retry a failed download."""
|
"""Retry a failed download."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def try_retry(self):
|
||||||
|
"""Try to retry a download and show an error if it's unsupported."""
|
||||||
|
try:
|
||||||
|
self.retry()
|
||||||
|
except UnsupportedOperationError as e:
|
||||||
|
message.error(str(e))
|
||||||
|
|
||||||
def _get_open_filename(self):
|
def _get_open_filename(self):
|
||||||
"""Get the filename to open a download.
|
"""Get the filename to open a download.
|
||||||
|
|
||||||
@ -968,7 +997,7 @@ class DownloadModel(QAbstractListModel):
|
|||||||
raise cmdexc.CommandError("No failed downloads!")
|
raise cmdexc.CommandError("No failed downloads!")
|
||||||
else:
|
else:
|
||||||
download = to_retry[0]
|
download = to_retry[0]
|
||||||
download.retry()
|
download.try_retry()
|
||||||
|
|
||||||
def can_clear(self):
|
def can_clear(self):
|
||||||
"""Check if there are finished downloads to clear."""
|
"""Check if there are finished downloads to clear."""
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -23,7 +23,7 @@ import functools
|
|||||||
|
|
||||||
import sip
|
import sip
|
||||||
from PyQt5.QtCore import pyqtSlot, QSize, Qt, QTimer
|
from PyQt5.QtCore import pyqtSlot, QSize, Qt, QTimer
|
||||||
from PyQt5.QtWidgets import QListView, QSizePolicy, QMenu
|
from PyQt5.QtWidgets import QListView, QSizePolicy, QMenu, QStyleFactory
|
||||||
|
|
||||||
from qutebrowser.browser import downloads
|
from qutebrowser.browser import downloads
|
||||||
from qutebrowser.config import style
|
from qutebrowser.config import style
|
||||||
@ -75,6 +75,7 @@ class DownloadView(QListView):
|
|||||||
|
|
||||||
def __init__(self, win_id, parent=None):
|
def __init__(self, win_id, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
self.setStyle(QStyleFactory.create('Fusion'))
|
||||||
style.set_register_stylesheet(self)
|
style.set_register_stylesheet(self)
|
||||||
self.setResizeMode(QListView.Adjust)
|
self.setResizeMode(QListView.Adjust)
|
||||||
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
@ -134,7 +135,7 @@ class DownloadView(QListView):
|
|||||||
if item.successful:
|
if item.successful:
|
||||||
actions.append(("Open", item.open_file))
|
actions.append(("Open", item.open_file))
|
||||||
else:
|
else:
|
||||||
actions.append(("Retry", item.retry))
|
actions.append(("Retry", item.try_retry))
|
||||||
actions.append(("Remove", item.remove))
|
actions.append(("Remove", item.remove))
|
||||||
else:
|
else:
|
||||||
actions.append(("Cancel", item.cancel))
|
actions.append(("Cancel", item.cancel))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2015-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2015-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -155,7 +155,7 @@ class PACResolver:
|
|||||||
raise ParseProxyError("Invalid number of parameters for PROXY")
|
raise ParseProxyError("Invalid number of parameters for PROXY")
|
||||||
host, port = PACResolver._parse_proxy_host(config[1])
|
host, port = PACResolver._parse_proxy_host(config[1])
|
||||||
return QNetworkProxy(QNetworkProxy.HttpProxy, host, port)
|
return QNetworkProxy(QNetworkProxy.HttpProxy, host, port)
|
||||||
elif config[0] == "SOCKS":
|
elif config[0] in ["SOCKS", "SOCKS5"]:
|
||||||
if len(config) != 2:
|
if len(config) != 2:
|
||||||
raise ParseProxyError("Invalid number of parameters for SOCKS")
|
raise ParseProxyError("Invalid number of parameters for SOCKS")
|
||||||
host, port = PACResolver._parse_proxy_host(config[1])
|
host, port = PACResolver._parse_proxy_host(config[1])
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2015 Daniel Schadt
|
# Copyright 2015 Daniel Schadt
|
||||||
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -110,6 +110,9 @@ class DownloadItem(downloads.AbstractDownloadItem):
|
|||||||
def _do_die(self):
|
def _do_die(self):
|
||||||
"""Abort the download and emit an error."""
|
"""Abort the download and emit an error."""
|
||||||
self._read_timer.stop()
|
self._read_timer.stop()
|
||||||
|
if self._reply is None:
|
||||||
|
log.downloads.debug("Reply gone while dying")
|
||||||
|
return
|
||||||
self._reply.downloadProgress.disconnect()
|
self._reply.downloadProgress.disconnect()
|
||||||
self._reply.finished.disconnect()
|
self._reply.finished.disconnect()
|
||||||
self._reply.error.disconnect()
|
self._reply.error.disconnect()
|
||||||
@ -270,7 +273,7 @@ class DownloadItem(downloads.AbstractDownloadItem):
|
|||||||
if self.fileobj is None or self._reply is None:
|
if self.fileobj is None or self._reply is None:
|
||||||
# No filename has been set yet (so we don't empty the buffer) or we
|
# No filename has been set yet (so we don't empty the buffer) or we
|
||||||
# got a readyRead after the reply was finished (which happens on
|
# got a readyRead after the reply was finished (which happens on
|
||||||
# qute:log for example).
|
# qute://log for example).
|
||||||
return
|
return
|
||||||
if not self._reply.isOpen():
|
if not self._reply.isOpen():
|
||||||
raise OSError("Reply is closed!")
|
raise OSError("Reply is closed!")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -17,23 +17,26 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
"""Backend-independent qute:* code.
|
"""Backend-independent qute://* code.
|
||||||
|
|
||||||
Module attributes:
|
Module attributes:
|
||||||
pyeval_output: The output of the last :pyeval command.
|
pyeval_output: The output of the last :pyeval command.
|
||||||
_HANDLERS: The handlers registered via decorators.
|
_HANDLERS: The handlers registered via decorators.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import datetime
|
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
import datetime
|
||||||
|
|
||||||
from PyQt5.QtCore import QUrlQuery
|
from PyQt5.QtCore import QUrlQuery, QUrl
|
||||||
|
|
||||||
import qutebrowser
|
import qutebrowser
|
||||||
|
from qutebrowser.config import config
|
||||||
from qutebrowser.utils import (version, utils, jinja, log, message, docutils,
|
from qutebrowser.utils import (version, utils, jinja, log, message, docutils,
|
||||||
objreg)
|
objreg, usertypes, qtutils)
|
||||||
from qutebrowser.misc import objects
|
from qutebrowser.misc import objects
|
||||||
|
|
||||||
|
|
||||||
@ -75,12 +78,25 @@ class QuteSchemeError(Exception):
|
|||||||
super().__init__(errorstring)
|
super().__init__(errorstring)
|
||||||
|
|
||||||
|
|
||||||
class add_handler: # pylint: disable=invalid-name
|
class Redirect(Exception):
|
||||||
|
|
||||||
"""Decorator to register a qute:* URL handler.
|
"""Exception to signal a redirect should happen.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
_name: The 'foo' part of qute:foo
|
url: The URL to redirect to, as a QUrl.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, url):
|
||||||
|
super().__init__(url.toDisplayString())
|
||||||
|
self.url = url
|
||||||
|
|
||||||
|
|
||||||
|
class add_handler: # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
"""Decorator to register a qute://* URL handler.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
_name: The 'foo' part of qute://foo
|
||||||
backend: Limit which backends the handler can run with.
|
backend: Limit which backends the handler can run with.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -103,7 +119,7 @@ class add_handler: # pylint: disable=invalid-name
|
|||||||
def wrong_backend_handler(self, url):
|
def wrong_backend_handler(self, url):
|
||||||
"""Show an error page about using the invalid backend."""
|
"""Show an error page about using the invalid backend."""
|
||||||
html = jinja.render('error.html',
|
html = jinja.render('error.html',
|
||||||
title="Error while opening qute:url",
|
title="Error while opening qute://url",
|
||||||
url=url.toDisplayString(),
|
url=url.toDisplayString(),
|
||||||
error='{} is not available with this '
|
error='{} is not available with this '
|
||||||
'backend'.format(url.toDisplayString()),
|
'backend'.format(url.toDisplayString()),
|
||||||
@ -125,13 +141,19 @@ def data_for_url(url):
|
|||||||
# A url like "qute:foo" is split as "scheme:path", not "scheme:host".
|
# A url like "qute:foo" is split as "scheme:path", not "scheme:host".
|
||||||
log.misc.debug("url: {}, path: {}, host {}".format(
|
log.misc.debug("url: {}, path: {}, host {}".format(
|
||||||
url.toDisplayString(), path, host))
|
url.toDisplayString(), path, host))
|
||||||
try:
|
if path and not host:
|
||||||
handler = _HANDLERS[path]
|
new_url = QUrl()
|
||||||
except KeyError:
|
new_url.setScheme('qute')
|
||||||
|
new_url.setHost(path)
|
||||||
|
new_url.setPath('/')
|
||||||
|
if new_url.host(): # path was a valid host
|
||||||
|
raise Redirect(new_url)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
handler = _HANDLERS[host]
|
handler = _HANDLERS[host]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise NoHandlerFound(url)
|
raise NoHandlerFound(url)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
mimetype, data = handler(url)
|
mimetype, data = handler(url)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
@ -150,7 +172,7 @@ def data_for_url(url):
|
|||||||
|
|
||||||
@add_handler('bookmarks')
|
@add_handler('bookmarks')
|
||||||
def qute_bookmarks(_url):
|
def qute_bookmarks(_url):
|
||||||
"""Handler for qute:bookmarks. Display all quickmarks / bookmarks."""
|
"""Handler for qute://bookmarks. Display all quickmarks / bookmarks."""
|
||||||
bookmarks = sorted(objreg.get('bookmark-manager').marks.items(),
|
bookmarks = sorted(objreg.get('bookmark-manager').marks.items(),
|
||||||
key=lambda x: x[1]) # Sort by title
|
key=lambda x: x[1]) # Sort by title
|
||||||
quickmarks = sorted(objreg.get('quickmark-manager').marks.items(),
|
quickmarks = sorted(objreg.get('quickmark-manager').marks.items(),
|
||||||
@ -163,90 +185,160 @@ def qute_bookmarks(_url):
|
|||||||
return 'text/html', html
|
return 'text/html', html
|
||||||
|
|
||||||
|
|
||||||
@add_handler('history') # noqa
|
def history_data(start_time): # noqa
|
||||||
def qute_history(url):
|
"""Return history data
|
||||||
"""Handler for qute:history. Display history."""
|
|
||||||
# Get current date from query parameter, if not given choose today.
|
|
||||||
curr_date = datetime.date.today()
|
|
||||||
try:
|
|
||||||
query_date = QUrlQuery(url).queryItemValue("date")
|
|
||||||
if query_date:
|
|
||||||
curr_date = datetime.datetime.strptime(query_date, "%Y-%m-%d")
|
|
||||||
curr_date = curr_date.date()
|
|
||||||
except ValueError:
|
|
||||||
log.misc.debug("Invalid date passed to qute:history: " + query_date)
|
|
||||||
|
|
||||||
one_day = datetime.timedelta(days=1)
|
Arguments:
|
||||||
next_date = curr_date + one_day
|
start_time -- select history starting from this timestamp.
|
||||||
prev_date = curr_date - one_day
|
"""
|
||||||
|
def history_iter(start_time, reverse=False):
|
||||||
|
"""Iterate through the history and get items we're interested.
|
||||||
|
|
||||||
def history_iter(reverse):
|
Arguments:
|
||||||
"""Iterate through the history and get items we're interested in."""
|
reverse -- whether to reverse the history_dict before iterating.
|
||||||
curr_timestamp = time.mktime(curr_date.timetuple())
|
"""
|
||||||
history = objreg.get('web-history').history_dict.values()
|
history = objreg.get('web-history').history_dict.values()
|
||||||
if reverse:
|
if reverse:
|
||||||
history = reversed(history)
|
history = reversed(history)
|
||||||
|
|
||||||
|
# when history_dict is not reversed, we need to keep track of last item
|
||||||
|
# so that we can yield its atime
|
||||||
|
last_item = None
|
||||||
|
|
||||||
|
# end is 24hrs earlier than start
|
||||||
|
end_time = start_time - 24*60*60
|
||||||
|
|
||||||
for item in history:
|
for item in history:
|
||||||
# If we can't apply the reverse performance trick below,
|
|
||||||
# at least continue as early as possible with old items.
|
|
||||||
# This gets us down from 550ms to 123ms with 500k old items on my
|
|
||||||
# machine.
|
|
||||||
if item.atime < curr_timestamp and not reverse:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Convert timestamp
|
|
||||||
try:
|
|
||||||
item_atime = datetime.datetime.fromtimestamp(item.atime)
|
|
||||||
except (ValueError, OSError, OverflowError):
|
|
||||||
log.misc.debug("Invalid timestamp {}.".format(item.atime))
|
|
||||||
continue
|
|
||||||
|
|
||||||
if reverse and item_atime.date() < curr_date:
|
|
||||||
# If we could reverse the history in-place, and this entry is
|
|
||||||
# older than today, only older entries will follow, so we can
|
|
||||||
# abort here.
|
|
||||||
return
|
|
||||||
|
|
||||||
# Skip items not on curr_date
|
|
||||||
# Skip redirects
|
# Skip redirects
|
||||||
# Skip qute:// links
|
# Skip qute:// links
|
||||||
is_internal = item.url.scheme() == 'qute'
|
if item.redirect or item.url.scheme() == 'qute':
|
||||||
is_not_today = item_atime.date() != curr_date
|
|
||||||
if item.redirect or is_internal or is_not_today:
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Skip items out of time window
|
||||||
|
item_newer = item.atime > start_time
|
||||||
|
item_older = item.atime <= end_time
|
||||||
|
if reverse:
|
||||||
|
# history_dict is reversed, we are going back in history.
|
||||||
|
# so:
|
||||||
|
# abort if item is older than start_time+24hr
|
||||||
|
# skip if item is newer than start
|
||||||
|
if item_older:
|
||||||
|
yield {"next": int(item.atime)}
|
||||||
|
return
|
||||||
|
if item_newer:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
# history_dict isn't reversed, we are going forward in history.
|
||||||
|
# so:
|
||||||
|
# abort if item is newer than start_time
|
||||||
|
# skip if item is older than start_time+24hrs
|
||||||
|
if item_older:
|
||||||
|
last_item = item
|
||||||
|
continue
|
||||||
|
if item_newer:
|
||||||
|
yield {"next": int(last_item.atime if last_item else -1)}
|
||||||
|
return
|
||||||
|
|
||||||
# Use item's url as title if there's no title.
|
# Use item's url as title if there's no title.
|
||||||
item_url = item.url.toDisplayString()
|
item_url = item.url.toDisplayString()
|
||||||
item_title = item.title if item.title else item_url
|
item_title = item.title if item.title else item_url
|
||||||
display_atime = item_atime.strftime("%X")
|
item_time = int(item.atime * 1000)
|
||||||
|
|
||||||
yield (item_url, item_title, display_atime)
|
yield {"url": item_url, "title": item_title, "time": item_time}
|
||||||
|
|
||||||
|
# if we reached here, we had reached the end of history
|
||||||
|
yield {"next": int(last_item.atime if last_item else -1)}
|
||||||
|
|
||||||
if sys.hexversion >= 0x03050000:
|
if sys.hexversion >= 0x03050000:
|
||||||
# On Python >= 3.5 we can reverse the ordereddict in-place and thus
|
# On Python >= 3.5 we can reverse the ordereddict in-place and thus
|
||||||
# apply an additional performance improvement in history_iter.
|
# apply an additional performance improvement in history_iter.
|
||||||
# On my machine, this gets us down from 550ms to 72us with 500k old
|
# On my machine, this gets us down from 550ms to 72us with 500k old
|
||||||
# items.
|
# items.
|
||||||
history = list(history_iter(reverse=True))
|
history = history_iter(start_time, reverse=True)
|
||||||
else:
|
else:
|
||||||
# On Python 3.4, we can't do that, so we'd need to copy the entire
|
# On Python 3.4, we can't do that, so we'd need to copy the entire
|
||||||
# history to a list. There, filter first and then reverse it here.
|
# history to a list. There, filter first and then reverse it here.
|
||||||
history = reversed(list(history_iter(reverse=False)))
|
history = reversed(list(history_iter(start_time, reverse=False)))
|
||||||
|
|
||||||
html = jinja.render('history.html',
|
return list(history)
|
||||||
|
|
||||||
|
|
||||||
|
@add_handler('history')
|
||||||
|
def qute_history(url):
|
||||||
|
"""Handler for qute://history. Display and serve history."""
|
||||||
|
if url.path() == '/data':
|
||||||
|
# Use start_time in query or current time.
|
||||||
|
try:
|
||||||
|
start_time = QUrlQuery(url).queryItemValue("start_time")
|
||||||
|
start_time = float(start_time) if start_time else time.time()
|
||||||
|
except ValueError as e:
|
||||||
|
raise QuteSchemeError("Query parameter start_time is invalid", e)
|
||||||
|
|
||||||
|
return 'text/html', json.dumps(history_data(start_time))
|
||||||
|
else:
|
||||||
|
if (
|
||||||
|
config.get('content', 'allow-javascript') and
|
||||||
|
(objects.backend == usertypes.Backend.QtWebEngine or
|
||||||
|
qtutils.is_qtwebkit_ng())
|
||||||
|
):
|
||||||
|
return 'text/html', jinja.render(
|
||||||
|
'history.html',
|
||||||
|
title='History',
|
||||||
|
session_interval=config.get('ui', 'history-session-interval')
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Get current date from query parameter, if not given choose today.
|
||||||
|
curr_date = datetime.date.today()
|
||||||
|
try:
|
||||||
|
query_date = QUrlQuery(url).queryItemValue("date")
|
||||||
|
if query_date:
|
||||||
|
curr_date = datetime.datetime.strptime(query_date,
|
||||||
|
"%Y-%m-%d").date()
|
||||||
|
except ValueError:
|
||||||
|
log.misc.debug("Invalid date passed to qute:history: " +
|
||||||
|
query_date)
|
||||||
|
|
||||||
|
one_day = datetime.timedelta(days=1)
|
||||||
|
next_date = curr_date + one_day
|
||||||
|
prev_date = curr_date - one_day
|
||||||
|
|
||||||
|
# start_time is the last second of curr_date
|
||||||
|
start_time = time.mktime(next_date.timetuple()) - 1
|
||||||
|
history = [
|
||||||
|
(i["url"], i["title"],
|
||||||
|
datetime.datetime.fromtimestamp(i["time"]/1000),
|
||||||
|
QUrl(i["url"]).host())
|
||||||
|
for i in history_data(start_time) if "next" not in i
|
||||||
|
]
|
||||||
|
|
||||||
|
return 'text/html', jinja.render(
|
||||||
|
'history_nojs.html',
|
||||||
title='History',
|
title='History',
|
||||||
history=history,
|
history=history,
|
||||||
curr_date=curr_date,
|
curr_date=curr_date,
|
||||||
next_date=next_date,
|
next_date=next_date,
|
||||||
prev_date=prev_date,
|
prev_date=prev_date,
|
||||||
today=datetime.date.today())
|
today=datetime.date.today(),
|
||||||
return 'text/html', html
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@add_handler('javascript')
|
||||||
|
def qute_javascript(url):
|
||||||
|
"""Handler for qute://javascript.
|
||||||
|
|
||||||
|
Return content of file given as query parameter.
|
||||||
|
"""
|
||||||
|
path = url.path()
|
||||||
|
if path:
|
||||||
|
path = "javascript" + os.sep.join(path.split('/'))
|
||||||
|
return 'text/html', utils.read_file(path, binary=False)
|
||||||
|
else:
|
||||||
|
raise QuteSchemeError("No file specified", ValueError())
|
||||||
|
|
||||||
|
|
||||||
@add_handler('pyeval')
|
@add_handler('pyeval')
|
||||||
def qute_pyeval(_url):
|
def qute_pyeval(_url):
|
||||||
"""Handler for qute:pyeval."""
|
"""Handler for qute://pyeval."""
|
||||||
html = jinja.render('pre.html', title='pyeval', content=pyeval_output)
|
html = jinja.render('pre.html', title='pyeval', content=pyeval_output)
|
||||||
return 'text/html', html
|
return 'text/html', html
|
||||||
|
|
||||||
@ -254,7 +346,7 @@ def qute_pyeval(_url):
|
|||||||
@add_handler('version')
|
@add_handler('version')
|
||||||
@add_handler('verizon')
|
@add_handler('verizon')
|
||||||
def qute_version(_url):
|
def qute_version(_url):
|
||||||
"""Handler for qute:version."""
|
"""Handler for qute://version."""
|
||||||
html = jinja.render('version.html', title='Version info',
|
html = jinja.render('version.html', title='Version info',
|
||||||
version=version.version(),
|
version=version.version(),
|
||||||
copyright=qutebrowser.__copyright__)
|
copyright=qutebrowser.__copyright__)
|
||||||
@ -263,7 +355,7 @@ def qute_version(_url):
|
|||||||
|
|
||||||
@add_handler('plainlog')
|
@add_handler('plainlog')
|
||||||
def qute_plainlog(url):
|
def qute_plainlog(url):
|
||||||
"""Handler for qute:plainlog.
|
"""Handler for qute://plainlog.
|
||||||
|
|
||||||
An optional query parameter specifies the minimum log level to print.
|
An optional query parameter specifies the minimum log level to print.
|
||||||
For example, qute://log?level=warning prints warnings and errors.
|
For example, qute://log?level=warning prints warnings and errors.
|
||||||
@ -283,7 +375,7 @@ def qute_plainlog(url):
|
|||||||
|
|
||||||
@add_handler('log')
|
@add_handler('log')
|
||||||
def qute_log(url):
|
def qute_log(url):
|
||||||
"""Handler for qute:log.
|
"""Handler for qute://log.
|
||||||
|
|
||||||
An optional query parameter specifies the minimum log level to print.
|
An optional query parameter specifies the minimum log level to print.
|
||||||
For example, qute://log?level=warning prints warnings and errors.
|
For example, qute://log?level=warning prints warnings and errors.
|
||||||
@ -304,13 +396,13 @@ def qute_log(url):
|
|||||||
|
|
||||||
@add_handler('gpl')
|
@add_handler('gpl')
|
||||||
def qute_gpl(_url):
|
def qute_gpl(_url):
|
||||||
"""Handler for qute:gpl. Return HTML content as string."""
|
"""Handler for qute://gpl. Return HTML content as string."""
|
||||||
return 'text/html', utils.read_file('html/COPYING.html')
|
return 'text/html', utils.read_file('html/COPYING.html')
|
||||||
|
|
||||||
|
|
||||||
@add_handler('help')
|
@add_handler('help')
|
||||||
def qute_help(url):
|
def qute_help(url):
|
||||||
"""Handler for qute:help."""
|
"""Handler for qute://help."""
|
||||||
try:
|
try:
|
||||||
utils.read_file('html/doc/index.html')
|
utils.read_file('html/doc/index.html')
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
# Copyright 2015-2016 Antoni Boucher <bouanto@zoho.com>
|
# Copyright 2015-2017 Antoni Boucher <bouanto@zoho.com>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -306,6 +306,11 @@ class AbstractWebElement(collections.abc.MutableMapping):
|
|||||||
qtutils.ensure_valid(url)
|
qtutils.ensure_valid(url)
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
def is_link(self):
|
||||||
|
"""Return True if this AbstractWebElement is a link."""
|
||||||
|
href_tags = ['a', 'area', 'link']
|
||||||
|
return self.tag_name() in href_tags
|
||||||
|
|
||||||
def _mouse_pos(self):
|
def _mouse_pos(self):
|
||||||
"""Get the position to click/hover."""
|
"""Get the position to click/hover."""
|
||||||
# Click the center of the largest square fitting into the top/left
|
# Click the center of the largest square fitting into the top/left
|
||||||
@ -403,9 +408,8 @@ class AbstractWebElement(collections.abc.MutableMapping):
|
|||||||
self._click_fake_event(click_target)
|
self._click_fake_event(click_target)
|
||||||
return
|
return
|
||||||
|
|
||||||
href_tags = ['a', 'area', 'link']
|
|
||||||
if click_target == usertypes.ClickTarget.normal:
|
if click_target == usertypes.ClickTarget.normal:
|
||||||
if self.tag_name() in href_tags:
|
if self.is_link():
|
||||||
log.webelem.debug("Clicking via JS click()")
|
log.webelem.debug("Clicking via JS click()")
|
||||||
self._click_js(click_target)
|
self._click_js(click_target)
|
||||||
elif self.is_editable(strict=True):
|
elif self.is_editable(strict=True):
|
||||||
@ -418,7 +422,7 @@ class AbstractWebElement(collections.abc.MutableMapping):
|
|||||||
elif click_target in [usertypes.ClickTarget.tab,
|
elif click_target in [usertypes.ClickTarget.tab,
|
||||||
usertypes.ClickTarget.tab_bg,
|
usertypes.ClickTarget.tab_bg,
|
||||||
usertypes.ClickTarget.window]:
|
usertypes.ClickTarget.window]:
|
||||||
if self.tag_name() in href_tags:
|
if self.is_link():
|
||||||
self._click_href(click_target)
|
self._click_href(click_target)
|
||||||
else:
|
else:
|
||||||
self._click_fake_event(click_target)
|
self._click_fake_event(click_target)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -57,8 +57,7 @@ class RequestInterceptor(QWebEngineUrlRequestInterceptor):
|
|||||||
info: QWebEngineUrlRequestInfo &info
|
info: QWebEngineUrlRequestInfo &info
|
||||||
"""
|
"""
|
||||||
# FIXME:qtwebengine only block ads for NavigationTypeOther?
|
# FIXME:qtwebengine only block ads for NavigationTypeOther?
|
||||||
if (bytes(info.requestMethod()) == b'GET' and
|
if self._host_blocker.is_blocked(info.requestUrl()):
|
||||||
self._host_blocker.is_blocked(info.requestUrl())):
|
|
||||||
log.webview.info("Request to {} blocked by host blocker.".format(
|
log.webview.info("Request to {} blocked by host blocker.".format(
|
||||||
info.requestUrl().host()))
|
info.requestUrl().host()))
|
||||||
info.block(True)
|
info.block(True)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2015-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -78,16 +78,15 @@ class DownloadItem(downloads.AbstractDownloadItem):
|
|||||||
self.stats.finish()
|
self.stats.finish()
|
||||||
elif state == QWebEngineDownloadItem.DownloadInterrupted:
|
elif state == QWebEngineDownloadItem.DownloadInterrupted:
|
||||||
self.successful = False
|
self.successful = False
|
||||||
self.done = True
|
|
||||||
# https://bugreports.qt.io/browse/QTBUG-56839
|
# https://bugreports.qt.io/browse/QTBUG-56839
|
||||||
self.error.emit("Download failed")
|
self._die("Download failed")
|
||||||
self.stats.finish()
|
|
||||||
else:
|
else:
|
||||||
raise ValueError("_on_state_changed was called with unknown state "
|
raise ValueError("_on_state_changed was called with unknown state "
|
||||||
"{}".format(state_name))
|
"{}".format(state_name))
|
||||||
|
|
||||||
def _do_die(self):
|
def _do_die(self):
|
||||||
self._qt_item.downloadProgress.disconnect()
|
self._qt_item.downloadProgress.disconnect()
|
||||||
|
if self._qt_item.state() != QWebEngineDownloadItem.DownloadInterrupted:
|
||||||
self._qt_item.cancel()
|
self._qt_item.cancel()
|
||||||
|
|
||||||
def _do_cancel(self):
|
def _do_cancel(self):
|
||||||
@ -95,15 +94,18 @@ class DownloadItem(downloads.AbstractDownloadItem):
|
|||||||
|
|
||||||
def retry(self):
|
def retry(self):
|
||||||
# https://bugreports.qt.io/browse/QTBUG-56840
|
# https://bugreports.qt.io/browse/QTBUG-56840
|
||||||
raise downloads.UnsupportedOperationError
|
raise downloads.UnsupportedOperationError(
|
||||||
|
"Retrying downloads is unsupported with QtWebEngine")
|
||||||
|
|
||||||
def _get_open_filename(self):
|
def _get_open_filename(self):
|
||||||
return self._filename
|
return self._filename
|
||||||
|
|
||||||
def _set_fileobj(self, fileobj):
|
def _set_fileobj(self, fileobj, *,
|
||||||
|
autoclose=True): # pylint: disable=unused-argument
|
||||||
raise downloads.UnsupportedOperationError
|
raise downloads.UnsupportedOperationError
|
||||||
|
|
||||||
def _set_tempfile(self, fileobj):
|
def _set_tempfile(self, fileobj):
|
||||||
|
fileobj.close()
|
||||||
self._set_filename(fileobj.name, force_overwrite=True,
|
self._set_filename(fileobj.name, force_overwrite=True,
|
||||||
remember_directory=False)
|
remember_directory=False)
|
||||||
|
|
||||||
@ -145,7 +147,7 @@ def _get_suggested_filename(path):
|
|||||||
"""
|
"""
|
||||||
filename = os.path.basename(path)
|
filename = os.path.basename(path)
|
||||||
filename = re.sub(r'\([0-9]+\)(?=\.|$)', '', filename)
|
filename = re.sub(r'\([0-9]+\)(?=\.|$)', '', filename)
|
||||||
if not qtutils.version_check('5.8.1'):
|
if not qtutils.version_check('5.9'):
|
||||||
# https://bugreports.qt.io/browse/QTBUG-58155
|
# https://bugreports.qt.io/browse/QTBUG-58155
|
||||||
filename = urllib.parse.unquote(filename)
|
filename = urllib.parse.unquote(filename)
|
||||||
# Doing basename a *second* time because there could be a %2F in
|
# Doing basename a *second* time because there could be a %2F in
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -18,7 +18,7 @@
|
|||||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# FIXME:qtwebengine remove this once the stubs are gone
|
# FIXME:qtwebengine remove this once the stubs are gone
|
||||||
# pylint: disable=unused-variable
|
# pylint: disable=unused-argument
|
||||||
|
|
||||||
"""QtWebEngine specific part of the web element API."""
|
"""QtWebEngine specific part of the web element API."""
|
||||||
|
|
||||||
@ -39,6 +39,38 @@ class WebEngineElement(webelem.AbstractWebElement):
|
|||||||
|
|
||||||
def __init__(self, js_dict, tab):
|
def __init__(self, js_dict, tab):
|
||||||
super().__init__(tab)
|
super().__init__(tab)
|
||||||
|
# Do some sanity checks on the data we get from JS
|
||||||
|
js_dict_types = {
|
||||||
|
'id': int,
|
||||||
|
'text': str,
|
||||||
|
'value': (str, int, float),
|
||||||
|
'tag_name': str,
|
||||||
|
'outer_xml': str,
|
||||||
|
'class_name': str,
|
||||||
|
'rects': list,
|
||||||
|
'attributes': dict,
|
||||||
|
}
|
||||||
|
assert set(js_dict.keys()).issubset(js_dict_types.keys())
|
||||||
|
for name, typ in js_dict_types.items():
|
||||||
|
if name in js_dict and not isinstance(js_dict[name], typ):
|
||||||
|
raise TypeError("Got {} for {} from JS but expected {}: "
|
||||||
|
"{}".format(type(js_dict[name]), name, typ,
|
||||||
|
js_dict))
|
||||||
|
for name, value in js_dict['attributes'].items():
|
||||||
|
if not isinstance(name, str):
|
||||||
|
raise TypeError("Got {} ({}) for attribute name from JS: "
|
||||||
|
"{}".format(name, type(name), js_dict))
|
||||||
|
if not isinstance(value, str):
|
||||||
|
raise TypeError("Got {} ({}) for attribute {} from JS: "
|
||||||
|
"{}".format(value, type(value), name, js_dict))
|
||||||
|
for rect in js_dict['rects']:
|
||||||
|
assert set(rect.keys()) == {'top', 'right', 'bottom', 'left',
|
||||||
|
'height', 'width'}, rect.keys()
|
||||||
|
for value in rect.values():
|
||||||
|
if not isinstance(value, (int, float)):
|
||||||
|
raise TypeError("Got {} ({}) for rect from JS: "
|
||||||
|
"{}".format(value, type(value), js_dict))
|
||||||
|
|
||||||
self._id = js_dict['id']
|
self._id = js_dict['id']
|
||||||
self._js_dict = js_dict
|
self._js_dict = js_dict
|
||||||
|
|
||||||
@ -88,7 +120,9 @@ class WebEngineElement(webelem.AbstractWebElement):
|
|||||||
|
|
||||||
The returned name will always be lower-case.
|
The returned name will always be lower-case.
|
||||||
"""
|
"""
|
||||||
return self._js_dict['tag_name'].lower()
|
tag = self._js_dict['tag_name']
|
||||||
|
assert isinstance(tag, str), tag
|
||||||
|
return tag.lower()
|
||||||
|
|
||||||
def outer_xml(self):
|
def outer_xml(self):
|
||||||
"""Get the full HTML representation of this element."""
|
"""Get the full HTML representation of this element."""
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2015-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -17,7 +17,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
"""QtWebEngine specific qute:* handlers and glue code."""
|
"""QtWebEngine specific qute://* handlers and glue code."""
|
||||||
|
|
||||||
from PyQt5.QtCore import QBuffer, QIODevice
|
from PyQt5.QtCore import QBuffer, QIODevice
|
||||||
# pylint: disable=no-name-in-module,import-error,useless-suppression
|
# pylint: disable=no-name-in-module,import-error,useless-suppression
|
||||||
@ -26,15 +26,15 @@ from PyQt5.QtWebEngineCore import (QWebEngineUrlSchemeHandler,
|
|||||||
# pylint: enable=no-name-in-module,import-error,useless-suppression
|
# pylint: enable=no-name-in-module,import-error,useless-suppression
|
||||||
|
|
||||||
from qutebrowser.browser import qutescheme
|
from qutebrowser.browser import qutescheme
|
||||||
from qutebrowser.utils import log
|
from qutebrowser.utils import log, qtutils
|
||||||
|
|
||||||
|
|
||||||
class QuteSchemeHandler(QWebEngineUrlSchemeHandler):
|
class QuteSchemeHandler(QWebEngineUrlSchemeHandler):
|
||||||
|
|
||||||
"""Handle qute:* requests on QtWebEngine."""
|
"""Handle qute://* requests on QtWebEngine."""
|
||||||
|
|
||||||
def install(self, profile):
|
def install(self, profile):
|
||||||
"""Install the handler for qute: URLs on the given profile."""
|
"""Install the handler for qute:// URLs on the given profile."""
|
||||||
profile.installUrlSchemeHandler(b'qute', self)
|
profile.installUrlSchemeHandler(b'qute', self)
|
||||||
|
|
||||||
def requestStarted(self, job):
|
def requestStarted(self, job):
|
||||||
@ -58,12 +58,15 @@ class QuteSchemeHandler(QWebEngineUrlSchemeHandler):
|
|||||||
job.fail(QWebEngineUrlRequestJob.UrlNotFound)
|
job.fail(QWebEngineUrlRequestJob.UrlNotFound)
|
||||||
except qutescheme.QuteSchemeOSError:
|
except qutescheme.QuteSchemeOSError:
|
||||||
# FIXME:qtwebengine how do we show a better error here?
|
# FIXME:qtwebengine how do we show a better error here?
|
||||||
log.misc.exception("OSError while handling qute:* URL")
|
log.misc.exception("OSError while handling qute://* URL")
|
||||||
job.fail(QWebEngineUrlRequestJob.UrlNotFound)
|
job.fail(QWebEngineUrlRequestJob.UrlNotFound)
|
||||||
except qutescheme.QuteSchemeError:
|
except qutescheme.QuteSchemeError:
|
||||||
# FIXME:qtwebengine how do we show a better error here?
|
# FIXME:qtwebengine how do we show a better error here?
|
||||||
log.misc.exception("Error while handling qute:* URL")
|
log.misc.exception("Error while handling qute://* URL")
|
||||||
job.fail(QWebEngineUrlRequestJob.RequestFailed)
|
job.fail(QWebEngineUrlRequestJob.RequestFailed)
|
||||||
|
except qutescheme.Redirect as e:
|
||||||
|
qtutils.ensure_valid(e.url)
|
||||||
|
job.redirect(e.url)
|
||||||
else:
|
else:
|
||||||
log.misc.debug("Returning {} data".format(mimetype))
|
log.misc.debug("Returning {} data".format(mimetype))
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -34,7 +34,8 @@ from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile,
|
|||||||
|
|
||||||
from qutebrowser.browser import shared
|
from qutebrowser.browser import shared
|
||||||
from qutebrowser.config import config, websettings
|
from qutebrowser.config import config, websettings
|
||||||
from qutebrowser.utils import objreg, utils, standarddir, javascript, log
|
from qutebrowser.utils import (objreg, utils, standarddir, javascript, log,
|
||||||
|
qtutils)
|
||||||
|
|
||||||
|
|
||||||
class Attribute(websettings.Attribute):
|
class Attribute(websettings.Attribute):
|
||||||
@ -177,6 +178,7 @@ def init(args):
|
|||||||
_init_stylesheet(profile)
|
_init_stylesheet(profile)
|
||||||
# We need to do this here as a WORKAROUND for
|
# We need to do this here as a WORKAROUND for
|
||||||
# https://bugreports.qt.io/browse/QTBUG-58650
|
# https://bugreports.qt.io/browse/QTBUG-58650
|
||||||
|
if not qtutils.version_check('5.9'):
|
||||||
PersistentCookiePolicy().set(config.get('content', 'cookies-store'))
|
PersistentCookiePolicy().set(config.get('content', 'cookies-store'))
|
||||||
|
|
||||||
Attribute(QWebEngineSettings.FullScreenSupportEnabled).set(True)
|
Attribute(QWebEngineSettings.FullScreenSupportEnabled).set(True)
|
||||||
@ -221,9 +223,6 @@ MAPPINGS = {
|
|||||||
Attribute(QWebEngineSettings.LocalContentCanAccessRemoteUrls),
|
Attribute(QWebEngineSettings.LocalContentCanAccessRemoteUrls),
|
||||||
'local-content-can-access-file-urls':
|
'local-content-can-access-file-urls':
|
||||||
Attribute(QWebEngineSettings.LocalContentCanAccessFileUrls),
|
Attribute(QWebEngineSettings.LocalContentCanAccessFileUrls),
|
||||||
# https://bugreports.qt.io/browse/QTBUG-58650
|
|
||||||
# 'cookies-store':
|
|
||||||
# PersistentCookiePolicy(),
|
|
||||||
'webgl':
|
'webgl':
|
||||||
Attribute(QWebEngineSettings.WebGLEnabled),
|
Attribute(QWebEngineSettings.WebGLEnabled),
|
||||||
},
|
},
|
||||||
@ -301,3 +300,8 @@ try:
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
# Added in Qt 5.8
|
# Added in Qt 5.8
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if qtutils.version_check('5.9'):
|
||||||
|
# https://bugreports.qt.io/browse/QTBUG-58650
|
||||||
|
MAPPINGS['content']['cookies-store'] = PersistentCookiePolicy()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -17,9 +17,6 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# FIXME:qtwebengine remove this once the stubs are gone
|
|
||||||
# pylint: disable=unused-variable
|
|
||||||
|
|
||||||
"""Wrapper over a QWebEngineView."""
|
"""Wrapper over a QWebEngineView."""
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
@ -40,7 +37,7 @@ from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
|
|||||||
webenginedownloads)
|
webenginedownloads)
|
||||||
from qutebrowser.misc import miscwidgets
|
from qutebrowser.misc import miscwidgets
|
||||||
from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils,
|
from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils,
|
||||||
objreg, jinja)
|
objreg, jinja, debug)
|
||||||
|
|
||||||
|
|
||||||
_qute_scheme_handler = None
|
_qute_scheme_handler = None
|
||||||
@ -55,7 +52,7 @@ def init():
|
|||||||
app = QApplication.instance()
|
app = QApplication.instance()
|
||||||
profile = QWebEngineProfile.defaultProfile()
|
profile = QWebEngineProfile.defaultProfile()
|
||||||
|
|
||||||
log.init.debug("Initializing qute:* handler...")
|
log.init.debug("Initializing qute://* handler...")
|
||||||
_qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(parent=app)
|
_qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(parent=app)
|
||||||
_qute_scheme_handler.install(profile)
|
_qute_scheme_handler.install(profile)
|
||||||
|
|
||||||
@ -82,17 +79,17 @@ _JS_WORLD_MAP = {
|
|||||||
|
|
||||||
class WebEngineAction(browsertab.AbstractAction):
|
class WebEngineAction(browsertab.AbstractAction):
|
||||||
|
|
||||||
"""QtWebKit implementations related to web actions."""
|
"""QtWebEngine implementations related to web actions."""
|
||||||
|
|
||||||
def _action(self, action):
|
action_class = QWebEnginePage
|
||||||
self._widget.triggerPageAction(action)
|
action_base = QWebEnginePage.WebAction
|
||||||
|
|
||||||
def exit_fullscreen(self):
|
def exit_fullscreen(self):
|
||||||
self._action(QWebEnginePage.ExitFullScreen)
|
self._widget.triggerPageAction(QWebEnginePage.ExitFullScreen)
|
||||||
|
|
||||||
def save_page(self):
|
def save_page(self):
|
||||||
"""Save the current page."""
|
"""Save the current page."""
|
||||||
self._action(QWebEnginePage.SavePage)
|
self._widget.triggerPageAction(QWebEnginePage.SavePage)
|
||||||
|
|
||||||
|
|
||||||
class WebEnginePrinting(browsertab.AbstractPrinting):
|
class WebEnginePrinting(browsertab.AbstractPrinting):
|
||||||
@ -128,12 +125,23 @@ class WebEngineSearch(browsertab.AbstractSearch):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._flags = QWebEnginePage.FindFlags(0)
|
self._flags = QWebEnginePage.FindFlags(0)
|
||||||
|
|
||||||
def _find(self, text, flags, cb=None):
|
def _find(self, text, flags, callback, caller):
|
||||||
"""Call findText on the widget with optional callback."""
|
"""Call findText on the widget."""
|
||||||
if cb is None:
|
self.search_displayed = True
|
||||||
self._widget.findText(text, flags)
|
|
||||||
|
def wrapped_callback(found):
|
||||||
|
"""Wrap the callback to do debug logging."""
|
||||||
|
found_text = 'found' if found else "didn't find"
|
||||||
|
if flags:
|
||||||
|
flag_text = 'with flags {}'.format(debug.qflags_key(
|
||||||
|
QWebEnginePage, flags, klass=QWebEnginePage.FindFlag))
|
||||||
else:
|
else:
|
||||||
self._widget.findText(text, flags, cb)
|
flag_text = ''
|
||||||
|
log.webview.debug(' '.join([caller, found_text, text, flag_text])
|
||||||
|
.strip())
|
||||||
|
if callback is not None:
|
||||||
|
callback(found)
|
||||||
|
self._widget.findText(text, flags, wrapped_callback)
|
||||||
|
|
||||||
def search(self, text, *, ignore_case=False, reverse=False,
|
def search(self, text, *, ignore_case=False, reverse=False,
|
||||||
result_cb=None):
|
result_cb=None):
|
||||||
@ -148,9 +156,10 @@ class WebEngineSearch(browsertab.AbstractSearch):
|
|||||||
|
|
||||||
self.text = text
|
self.text = text
|
||||||
self._flags = flags
|
self._flags = flags
|
||||||
self._find(text, flags, result_cb)
|
self._find(text, flags, result_cb, 'search')
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
|
self.search_displayed = False
|
||||||
self._widget.findText('')
|
self._widget.findText('')
|
||||||
|
|
||||||
def prev_result(self, *, result_cb=None):
|
def prev_result(self, *, result_cb=None):
|
||||||
@ -160,10 +169,10 @@ class WebEngineSearch(browsertab.AbstractSearch):
|
|||||||
flags &= ~QWebEnginePage.FindBackward
|
flags &= ~QWebEnginePage.FindBackward
|
||||||
else:
|
else:
|
||||||
flags |= QWebEnginePage.FindBackward
|
flags |= QWebEnginePage.FindBackward
|
||||||
self._find(self.text, flags, result_cb)
|
self._find(self.text, flags, result_cb, 'prev_result')
|
||||||
|
|
||||||
def next_result(self, *, result_cb=None):
|
def next_result(self, *, result_cb=None):
|
||||||
self._find(self.text, self._flags, result_cb)
|
self._find(self.text, self._flags, result_cb, 'next_result')
|
||||||
|
|
||||||
|
|
||||||
class WebEngineCaret(browsertab.AbstractCaret):
|
class WebEngineCaret(browsertab.AbstractCaret):
|
||||||
@ -237,8 +246,47 @@ class WebEngineCaret(browsertab.AbstractCaret):
|
|||||||
raise browsertab.UnsupportedOperationError
|
raise browsertab.UnsupportedOperationError
|
||||||
return self._widget.selectedText()
|
return self._widget.selectedText()
|
||||||
|
|
||||||
|
def _follow_selected_cb(self, js_elem, tab=False):
|
||||||
|
"""Callback for javascript which clicks the selected element.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
js_elem: The element serialized from javascript.
|
||||||
|
tab: Open in a new tab.
|
||||||
|
"""
|
||||||
|
if js_elem is None:
|
||||||
|
return
|
||||||
|
assert isinstance(js_elem, dict), js_elem
|
||||||
|
elem = webengineelem.WebEngineElement(js_elem, tab=self._tab)
|
||||||
|
if tab:
|
||||||
|
click_type = usertypes.ClickTarget.tab
|
||||||
|
else:
|
||||||
|
click_type = usertypes.ClickTarget.normal
|
||||||
|
|
||||||
|
# Only click if we see a link
|
||||||
|
if elem.is_link():
|
||||||
|
log.webview.debug("Found link in selection, clicking. ClickTarget "
|
||||||
|
"{}, elem {}".format(click_type, elem))
|
||||||
|
elem.click(click_type)
|
||||||
|
|
||||||
def follow_selected(self, *, tab=False):
|
def follow_selected(self, *, tab=False):
|
||||||
log.stub()
|
if self._tab.search.search_displayed:
|
||||||
|
# We are currently in search mode.
|
||||||
|
# let's click the link via a fake-click
|
||||||
|
# https://bugreports.qt.io/browse/QTBUG-60673
|
||||||
|
self._tab.search.clear()
|
||||||
|
|
||||||
|
log.webview.debug("Clicking a searched link via fake key press.")
|
||||||
|
# send a fake enter, clicking the orange selection box
|
||||||
|
if tab:
|
||||||
|
self._tab.key_press(Qt.Key_Enter, modifier=Qt.ControlModifier)
|
||||||
|
else:
|
||||||
|
self._tab.key_press(Qt.Key_Enter)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# click an existing blue selection
|
||||||
|
js_code = javascript.assemble('webelem', 'find_selected_link')
|
||||||
|
self._tab.run_js_async(js_code, lambda jsret:
|
||||||
|
self._follow_selected_cb(jsret, tab))
|
||||||
|
|
||||||
|
|
||||||
class WebEngineScroller(browsertab.AbstractScroller):
|
class WebEngineScroller(browsertab.AbstractScroller):
|
||||||
@ -256,13 +304,10 @@ class WebEngineScroller(browsertab.AbstractScroller):
|
|||||||
page = widget.page()
|
page = widget.page()
|
||||||
page.scrollPositionChanged.connect(self._update_pos)
|
page.scrollPositionChanged.connect(self._update_pos)
|
||||||
|
|
||||||
def _key_press(self, key, count=1):
|
def _repeated_key_press(self, key, count=1, modifier=Qt.NoModifier):
|
||||||
|
"""Send count fake key presses to this scroller's WebEngineTab."""
|
||||||
for _ in range(min(count, 5000)):
|
for _ in range(min(count, 5000)):
|
||||||
press_evt = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier, 0, 0, 0)
|
self._tab.key_press(key, modifier)
|
||||||
release_evt = QKeyEvent(QEvent.KeyRelease, key, Qt.NoModifier,
|
|
||||||
0, 0, 0)
|
|
||||||
self._tab.send_event(press_evt)
|
|
||||||
self._tab.send_event(release_evt)
|
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _update_pos(self):
|
def _update_pos(self):
|
||||||
@ -319,28 +364,28 @@ class WebEngineScroller(browsertab.AbstractScroller):
|
|||||||
self._tab.run_js_async(js_code)
|
self._tab.run_js_async(js_code)
|
||||||
|
|
||||||
def up(self, count=1):
|
def up(self, count=1):
|
||||||
self._key_press(Qt.Key_Up, count)
|
self._repeated_key_press(Qt.Key_Up, count)
|
||||||
|
|
||||||
def down(self, count=1):
|
def down(self, count=1):
|
||||||
self._key_press(Qt.Key_Down, count)
|
self._repeated_key_press(Qt.Key_Down, count)
|
||||||
|
|
||||||
def left(self, count=1):
|
def left(self, count=1):
|
||||||
self._key_press(Qt.Key_Left, count)
|
self._repeated_key_press(Qt.Key_Left, count)
|
||||||
|
|
||||||
def right(self, count=1):
|
def right(self, count=1):
|
||||||
self._key_press(Qt.Key_Right, count)
|
self._repeated_key_press(Qt.Key_Right, count)
|
||||||
|
|
||||||
def top(self):
|
def top(self):
|
||||||
self._key_press(Qt.Key_Home)
|
self._tab.key_press(Qt.Key_Home)
|
||||||
|
|
||||||
def bottom(self):
|
def bottom(self):
|
||||||
self._key_press(Qt.Key_End)
|
self._tab.key_press(Qt.Key_End)
|
||||||
|
|
||||||
def page_up(self, count=1):
|
def page_up(self, count=1):
|
||||||
self._key_press(Qt.Key_PageUp, count)
|
self._repeated_key_press(Qt.Key_PageUp, count)
|
||||||
|
|
||||||
def page_down(self, count=1):
|
def page_down(self, count=1):
|
||||||
self._key_press(Qt.Key_PageDown, count)
|
self._repeated_key_press(Qt.Key_PageDown, count)
|
||||||
|
|
||||||
def at_top(self):
|
def at_top(self):
|
||||||
return self.pos_px().y() == 0
|
return self.pos_px().y() == 0
|
||||||
@ -369,9 +414,13 @@ class WebEngineHistory(browsertab.AbstractHistory):
|
|||||||
return self._history.canGoForward()
|
return self._history.canGoForward()
|
||||||
|
|
||||||
def serialize(self):
|
def serialize(self):
|
||||||
# WORKAROUND for https://github.com/qutebrowser/qutebrowser/issues/2289
|
if not qtutils.version_check('5.9'):
|
||||||
# FIXME:qtwebengine can we get rid of this with Qt 5.8.1?
|
# WORKAROUND for
|
||||||
scheme = self._history.currentItem().url().scheme()
|
# https://github.com/qutebrowser/qutebrowser/issues/2289
|
||||||
|
# Don't use the history's currentItem here, because of
|
||||||
|
# https://bugreports.qt.io/browse/QTBUG-59599 and because it doesn't
|
||||||
|
# contain view-source.
|
||||||
|
scheme = self._tab.url().scheme()
|
||||||
if scheme in ['view-source', 'chrome']:
|
if scheme in ['view-source', 'chrome']:
|
||||||
raise browsertab.WebTabError("Can't serialize special URL!")
|
raise browsertab.WebTabError("Can't serialize special URL!")
|
||||||
return qtutils.serialize(self._history)
|
return qtutils.serialize(self._history)
|
||||||
@ -596,6 +645,13 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
def clear_ssl_errors(self):
|
def clear_ssl_errors(self):
|
||||||
raise browsertab.UnsupportedOperationError
|
raise browsertab.UnsupportedOperationError
|
||||||
|
|
||||||
|
def key_press(self, key, modifier=Qt.NoModifier):
|
||||||
|
press_evt = QKeyEvent(QEvent.KeyPress, key, modifier, 0, 0, 0)
|
||||||
|
release_evt = QKeyEvent(QEvent.KeyRelease, key, modifier,
|
||||||
|
0, 0, 0)
|
||||||
|
self.send_event(press_evt)
|
||||||
|
self.send_event(release_evt)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _on_history_trigger(self):
|
def _on_history_trigger(self):
|
||||||
url = self.url()
|
url = self.url()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -25,7 +25,7 @@ from PyQt5.QtCore import pyqtSlot
|
|||||||
from PyQt5.QtNetwork import QNetworkDiskCache, QNetworkCacheMetaData
|
from PyQt5.QtNetwork import QNetworkDiskCache, QNetworkCacheMetaData
|
||||||
|
|
||||||
from qutebrowser.config import config
|
from qutebrowser.config import config
|
||||||
from qutebrowser.utils import utils, objreg
|
from qutebrowser.utils import utils, objreg, qtutils
|
||||||
|
|
||||||
|
|
||||||
class DiskCache(QNetworkDiskCache):
|
class DiskCache(QNetworkDiskCache):
|
||||||
@ -53,6 +53,10 @@ class DiskCache(QNetworkDiskCache):
|
|||||||
size = config.get('storage', 'cache-size')
|
size = config.get('storage', 'cache-size')
|
||||||
if size is None:
|
if size is None:
|
||||||
size = 1024 * 1024 * 50 # default from QNetworkDiskCachePrivate
|
size = 1024 * 1024 * 50 # default from QNetworkDiskCachePrivate
|
||||||
|
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-59909
|
||||||
|
if (qtutils.version_check('5.7.1') and
|
||||||
|
not qtutils.version_check('5.9')): # pragma: no cover
|
||||||
|
size = 0
|
||||||
self.setMaximumCacheSize(size)
|
self.setMaximumCacheSize(size)
|
||||||
|
|
||||||
def _maybe_activate(self):
|
def _maybe_activate(self):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -41,7 +41,7 @@ class CertificateErrorWrapper(usertypes.AbstractCertificateErrorWrapper):
|
|||||||
try:
|
try:
|
||||||
# Qt >= 5.4
|
# Qt >= 5.4
|
||||||
return hash(self._error)
|
return hash(self._error)
|
||||||
except TypeError:
|
except TypeError: # pragma: no cover
|
||||||
return hash((self._error.certificate().toDer(),
|
return hash((self._error.certificate().toDer(),
|
||||||
self._error.error()))
|
self._error.error()))
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2015-2016 Daniel Schadt
|
# Copyright 2015-2017 Daniel Schadt
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
# Copyright 2015-2016 Antoni Boucher (antoyo) <bouanto@zoho.com>
|
# Copyright 2015-2017 Antoni Boucher (antoyo) <bouanto@zoho.com>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -416,8 +416,7 @@ class NetworkManager(QNetworkAccessManager):
|
|||||||
req.setRawHeader(header, value)
|
req.setRawHeader(header, value)
|
||||||
|
|
||||||
host_blocker = objreg.get('host-blocker')
|
host_blocker = objreg.get('host-blocker')
|
||||||
if (op == QNetworkAccessManager.GetOperation and
|
if host_blocker.is_blocked(req.url()):
|
||||||
host_blocker.is_blocked(req.url())):
|
|
||||||
log.webview.info("Request to {} blocked by host blocker.".format(
|
log.webview.info("Request to {} blocked by host blocker.".format(
|
||||||
req.url().host()))
|
req.url().host()))
|
||||||
return networkreply.ErrorNetworkReply(
|
return networkreply.ErrorNetworkReply(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# Based on the Eric5 helpviewer,
|
# Based on the Eric5 helpviewer,
|
||||||
# Copyright (c) 2009 - 2014 Detlev Offenbach <detlev@die-offenbachs.de>
|
# Copyright (c) 2009 - 2014 Detlev Offenbach <detlev@die-offenbachs.de>
|
||||||
@ -19,6 +19,10 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# For some reason, a segfault will be triggered if the unnecessary lambdas in
|
||||||
|
# this file aren't there.
|
||||||
|
# pylint: disable=unnecessary-lambda
|
||||||
|
|
||||||
"""Special network replies.."""
|
"""Special network replies.."""
|
||||||
|
|
||||||
@ -114,9 +118,6 @@ class ErrorNetworkReply(QNetworkReply):
|
|||||||
# the device to avoid getting a warning.
|
# the device to avoid getting a warning.
|
||||||
self.setOpenMode(QIODevice.ReadOnly)
|
self.setOpenMode(QIODevice.ReadOnly)
|
||||||
self.setError(error, errorstring)
|
self.setError(error, errorstring)
|
||||||
# For some reason, a segfault will be triggered if these lambdas aren't
|
|
||||||
# there.
|
|
||||||
# pylint: disable=unnecessary-lambda
|
|
||||||
QTimer.singleShot(0, lambda: self.error.emit(error))
|
QTimer.singleShot(0, lambda: self.error.emit(error))
|
||||||
QTimer.singleShot(0, lambda: self.finished.emit())
|
QTimer.singleShot(0, lambda: self.finished.emit())
|
||||||
|
|
||||||
@ -137,3 +138,20 @@ class ErrorNetworkReply(QNetworkReply):
|
|||||||
|
|
||||||
def isRunning(self):
|
def isRunning(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class RedirectNetworkReply(QNetworkReply):
|
||||||
|
|
||||||
|
"""A reply which redirects to the given URL."""
|
||||||
|
|
||||||
|
def __init__(self, new_url, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setAttribute(QNetworkRequest.RedirectionTargetAttribute, new_url)
|
||||||
|
QTimer.singleShot(0, lambda: self.finished.emit())
|
||||||
|
|
||||||
|
def abort(self):
|
||||||
|
"""Called when there's e.g. a redirection limit."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def readData(self, _maxlen):
|
||||||
|
return bytes()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# Based on the Eric5 helpviewer,
|
# Based on the Eric5 helpviewer,
|
||||||
# Copyright (c) 2009 - 2014 Detlev Offenbach <detlev@die-offenbachs.de>
|
# Copyright (c) 2009 - 2014 Detlev Offenbach <detlev@die-offenbachs.de>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -17,7 +17,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
"""QtWebKit specific qute:* handlers and glue code."""
|
"""QtWebKit specific qute://* handlers and glue code."""
|
||||||
|
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import functools
|
import functools
|
||||||
@ -28,13 +28,13 @@ from PyQt5.QtNetwork import QNetworkReply
|
|||||||
|
|
||||||
from qutebrowser.browser import pdfjs, qutescheme
|
from qutebrowser.browser import pdfjs, qutescheme
|
||||||
from qutebrowser.browser.webkit.network import schemehandler, networkreply
|
from qutebrowser.browser.webkit.network import schemehandler, networkreply
|
||||||
from qutebrowser.utils import jinja, log, message, objreg, usertypes
|
from qutebrowser.utils import jinja, log, message, objreg, usertypes, qtutils
|
||||||
from qutebrowser.config import configexc, configdata
|
from qutebrowser.config import configexc, configdata
|
||||||
|
|
||||||
|
|
||||||
class QuteSchemeHandler(schemehandler.SchemeHandler):
|
class QuteSchemeHandler(schemehandler.SchemeHandler):
|
||||||
|
|
||||||
"""Scheme handler for qute: URLs."""
|
"""Scheme handler for qute:// URLs."""
|
||||||
|
|
||||||
def createRequest(self, _op, request, _outgoing_data):
|
def createRequest(self, _op, request, _outgoing_data):
|
||||||
"""Create a new request.
|
"""Create a new request.
|
||||||
@ -62,6 +62,9 @@ class QuteSchemeHandler(schemehandler.SchemeHandler):
|
|||||||
except qutescheme.QuteSchemeError as e:
|
except qutescheme.QuteSchemeError as e:
|
||||||
return networkreply.ErrorNetworkReply(request, e.errorstring,
|
return networkreply.ErrorNetworkReply(request, e.errorstring,
|
||||||
e.error, self.parent())
|
e.error, self.parent())
|
||||||
|
except qutescheme.Redirect as e:
|
||||||
|
qtutils.ensure_valid(e.url)
|
||||||
|
return networkreply.RedirectNetworkReply(e.url, self.parent())
|
||||||
|
|
||||||
return networkreply.FixedDataNetworkReply(request, data, mimetype,
|
return networkreply.FixedDataNetworkReply(request, data, mimetype,
|
||||||
self.parent())
|
self.parent())
|
||||||
@ -69,15 +72,15 @@ class QuteSchemeHandler(schemehandler.SchemeHandler):
|
|||||||
|
|
||||||
class JSBridge(QObject):
|
class JSBridge(QObject):
|
||||||
|
|
||||||
"""Javascript-bridge for special qute:... pages."""
|
"""Javascript-bridge for special qute://... pages."""
|
||||||
|
|
||||||
@pyqtSlot(str, str, str)
|
@pyqtSlot(str, str, str)
|
||||||
def set(self, sectname, optname, value):
|
def set(self, sectname, optname, value):
|
||||||
"""Slot to set a setting from qute:settings."""
|
"""Slot to set a setting from qute://settings."""
|
||||||
# https://github.com/qutebrowser/qutebrowser/issues/727
|
# https://github.com/qutebrowser/qutebrowser/issues/727
|
||||||
if ((sectname, optname) == ('content', 'allow-javascript') and
|
if ((sectname, optname) == ('content', 'allow-javascript') and
|
||||||
value == 'false'):
|
value == 'false'):
|
||||||
message.error("Refusing to disable javascript via qute:settings "
|
message.error("Refusing to disable javascript via qute://settings "
|
||||||
"as it needs javascript support.")
|
"as it needs javascript support.")
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
@ -88,7 +91,7 @@ class JSBridge(QObject):
|
|||||||
|
|
||||||
@qutescheme.add_handler('settings', backend=usertypes.Backend.QtWebKit)
|
@qutescheme.add_handler('settings', backend=usertypes.Backend.QtWebKit)
|
||||||
def qute_settings(_url):
|
def qute_settings(_url):
|
||||||
"""Handler for qute:settings. View/change qute configuration."""
|
"""Handler for qute://settings. View/change qute configuration."""
|
||||||
config_getter = functools.partial(objreg.get('config').get, raw=True)
|
config_getter = functools.partial(objreg.get('config').get, raw=True)
|
||||||
html = jinja.render('settings.html', title='settings', config=configdata,
|
html = jinja.render('settings.html', title='settings', config=configdata,
|
||||||
confget=config_getter)
|
confget=config_getter)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -286,9 +286,6 @@ def normalize_ws(text):
|
|||||||
|
|
||||||
def parse_headers(content_disposition):
|
def parse_headers(content_disposition):
|
||||||
"""Build a _ContentDisposition from header values."""
|
"""Build a _ContentDisposition from header values."""
|
||||||
# WORKAROUND for https://bitbucket.org/logilab/pylint/issue/492/
|
|
||||||
# pylint: disable=no-member
|
|
||||||
|
|
||||||
# We allow non-ascii here (it will only be parsed inside of qdtext, and
|
# We allow non-ascii here (it will only be parsed inside of qdtext, and
|
||||||
# rejected by the grammar if it appears in other places), although parsing
|
# rejected by the grammar if it appears in other places), although parsing
|
||||||
# it can be ambiguous. Parsing it ensures that a non-ambiguous filename*
|
# it can be ambiguous. Parsing it ensures that a non-ambiguous filename*
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2015-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
|
|
||||||
from PyQt5.QtCore import QByteArray, QDataStream, QIODevice, QUrl
|
from PyQt5.QtCore import QByteArray, QDataStream, QIODevice, QUrl
|
||||||
from PyQt5.QtWebKit import qWebKitVersion
|
|
||||||
|
|
||||||
from qutebrowser.utils import qtutils
|
from qutebrowser.utils import qtutils
|
||||||
|
|
||||||
@ -181,7 +180,7 @@ def serialize(items):
|
|||||||
else:
|
else:
|
||||||
current_idx = 0
|
current_idx = 0
|
||||||
|
|
||||||
if qtutils.is_qtwebkit_ng(qWebKitVersion()):
|
if qtutils.is_qtwebkit_ng():
|
||||||
_serialize_ng(items, current_idx, stream)
|
_serialize_ng(items, current_idx, stream)
|
||||||
else:
|
else:
|
||||||
_serialize_old(items, current_idx, stream)
|
_serialize_old(items, current_idx, stream)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -112,7 +112,9 @@ class WebKitElement(webelem.AbstractWebElement):
|
|||||||
|
|
||||||
def value(self):
|
def value(self):
|
||||||
self._check_vanished()
|
self._check_vanished()
|
||||||
return self._elem.evaluateJavaScript('this.value')
|
val = self._elem.evaluateJavaScript('this.value')
|
||||||
|
assert isinstance(val, (int, float, str)), val
|
||||||
|
return val
|
||||||
|
|
||||||
def set_value(self, value):
|
def set_value(self, value):
|
||||||
self._check_vanished()
|
self._check_vanished()
|
||||||
@ -283,8 +285,7 @@ class WebKitElement(webelem.AbstractWebElement):
|
|||||||
for _ in range(5):
|
for _ in range(5):
|
||||||
if elem is None:
|
if elem is None:
|
||||||
break
|
break
|
||||||
tag = elem.tag_name()
|
if elem.is_link():
|
||||||
if tag == 'a' or tag == 'area':
|
|
||||||
if elem.get('target', None) == '_blank':
|
if elem.get('target', None) == '_blank':
|
||||||
elem['target'] = '_top'
|
elem['target'] = '_top'
|
||||||
break
|
break
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2015-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2015-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -26,7 +26,7 @@ Module attributes:
|
|||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
from PyQt5.QtWebKit import QWebSettings, qWebKitVersion
|
from PyQt5.QtWebKit import QWebSettings
|
||||||
|
|
||||||
from qutebrowser.config import config, websettings
|
from qutebrowser.config import config, websettings
|
||||||
from qutebrowser.utils import standarddir, objreg, urlutils, qtutils, message
|
from qutebrowser.utils import standarddir, objreg, urlutils, qtutils, message
|
||||||
@ -90,7 +90,7 @@ def _set_user_stylesheet():
|
|||||||
|
|
||||||
def _init_private_browsing():
|
def _init_private_browsing():
|
||||||
if config.get('general', 'private-browsing'):
|
if config.get('general', 'private-browsing'):
|
||||||
if qtutils.is_qtwebkit_ng(qWebKitVersion()):
|
if qtutils.is_qtwebkit_ng():
|
||||||
message.warning("Private browsing is not fully implemented by "
|
message.warning("Private browsing is not fully implemented by "
|
||||||
"QtWebKit-NG!")
|
"QtWebKit-NG!")
|
||||||
QWebSettings.setIconDatabasePath('')
|
QWebSettings.setIconDatabasePath('')
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -23,6 +23,7 @@ import sys
|
|||||||
import functools
|
import functools
|
||||||
import xml.etree.ElementTree
|
import xml.etree.ElementTree
|
||||||
|
|
||||||
|
import sip
|
||||||
from PyQt5.QtCore import (pyqtSlot, Qt, QEvent, QUrl, QPoint, QTimer, QSizeF,
|
from PyQt5.QtCore import (pyqtSlot, Qt, QEvent, QUrl, QPoint, QTimer, QSizeF,
|
||||||
QSize)
|
QSize)
|
||||||
from PyQt5.QtGui import QKeyEvent
|
from PyQt5.QtGui import QKeyEvent
|
||||||
@ -35,7 +36,7 @@ from qutebrowser.browser import browsertab
|
|||||||
from qutebrowser.browser.network import proxy
|
from qutebrowser.browser.network import proxy
|
||||||
from qutebrowser.browser.webkit import webview, tabhistory, webkitelem
|
from qutebrowser.browser.webkit import webview, tabhistory, webkitelem
|
||||||
from qutebrowser.browser.webkit.network import webkitqutescheme
|
from qutebrowser.browser.webkit.network import webkitqutescheme
|
||||||
from qutebrowser.utils import qtutils, objreg, usertypes, utils, log
|
from qutebrowser.utils import qtutils, objreg, usertypes, utils, log, debug
|
||||||
|
|
||||||
|
|
||||||
def init():
|
def init():
|
||||||
@ -56,6 +57,9 @@ class WebKitAction(browsertab.AbstractAction):
|
|||||||
|
|
||||||
"""QtWebKit implementations related to web actions."""
|
"""QtWebKit implementations related to web actions."""
|
||||||
|
|
||||||
|
action_class = QWebPage
|
||||||
|
action_base = QWebPage.WebAction
|
||||||
|
|
||||||
def exit_fullscreen(self):
|
def exit_fullscreen(self):
|
||||||
raise browsertab.UnsupportedOperationError
|
raise browsertab.UnsupportedOperationError
|
||||||
|
|
||||||
@ -103,7 +107,7 @@ class WebKitSearch(browsertab.AbstractSearch):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._flags = QWebPage.FindFlags(0)
|
self._flags = QWebPage.FindFlags(0)
|
||||||
|
|
||||||
def _call_cb(self, callback, found):
|
def _call_cb(self, callback, found, text, flags, caller):
|
||||||
"""Call the given callback if it's non-None.
|
"""Call the given callback if it's non-None.
|
||||||
|
|
||||||
Delays the call via a QTimer so the website is re-rendered in between.
|
Delays the call via a QTimer so the website is re-rendered in between.
|
||||||
@ -111,17 +115,34 @@ class WebKitSearch(browsertab.AbstractSearch):
|
|||||||
Args:
|
Args:
|
||||||
callback: What to call
|
callback: What to call
|
||||||
found: If the text was found
|
found: If the text was found
|
||||||
|
text: The text searched for
|
||||||
|
flags: The flags searched with
|
||||||
|
caller: Name of the caller.
|
||||||
"""
|
"""
|
||||||
|
found_text = 'found' if found else "didn't find"
|
||||||
|
# Removing FindWrapsAroundDocument to get the same logging as with
|
||||||
|
# QtWebEngine
|
||||||
|
debug_flags = debug.qflags_key(
|
||||||
|
QWebPage, flags & ~QWebPage.FindWrapsAroundDocument,
|
||||||
|
klass=QWebPage.FindFlag)
|
||||||
|
if debug_flags != '0x0000':
|
||||||
|
flag_text = 'with flags {}'.format(debug_flags)
|
||||||
|
else:
|
||||||
|
flag_text = ''
|
||||||
|
log.webview.debug(' '.join([caller, found_text, text, flag_text])
|
||||||
|
.strip())
|
||||||
if callback is not None:
|
if callback is not None:
|
||||||
QTimer.singleShot(0, functools.partial(callback, found))
|
QTimer.singleShot(0, functools.partial(callback, found))
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
|
self.search_displayed = False
|
||||||
# We first clear the marked text, then the highlights
|
# We first clear the marked text, then the highlights
|
||||||
self._widget.findText('')
|
self._widget.findText('')
|
||||||
self._widget.findText('', QWebPage.HighlightAllOccurrences)
|
self._widget.findText('', QWebPage.HighlightAllOccurrences)
|
||||||
|
|
||||||
def search(self, text, *, ignore_case=False, reverse=False,
|
def search(self, text, *, ignore_case=False, reverse=False,
|
||||||
result_cb=None):
|
result_cb=None):
|
||||||
|
self.search_displayed = True
|
||||||
flags = QWebPage.FindWrapsAroundDocument
|
flags = QWebPage.FindWrapsAroundDocument
|
||||||
if ignore_case == 'smart':
|
if ignore_case == 'smart':
|
||||||
if not text.islower():
|
if not text.islower():
|
||||||
@ -136,13 +157,15 @@ class WebKitSearch(browsertab.AbstractSearch):
|
|||||||
self._widget.findText(text, flags | QWebPage.HighlightAllOccurrences)
|
self._widget.findText(text, flags | QWebPage.HighlightAllOccurrences)
|
||||||
self.text = text
|
self.text = text
|
||||||
self._flags = flags
|
self._flags = flags
|
||||||
self._call_cb(result_cb, found)
|
self._call_cb(result_cb, found, text, flags, 'search')
|
||||||
|
|
||||||
def next_result(self, *, result_cb=None):
|
def next_result(self, *, result_cb=None):
|
||||||
|
self.search_displayed = True
|
||||||
found = self._widget.findText(self.text, self._flags)
|
found = self._widget.findText(self.text, self._flags)
|
||||||
self._call_cb(result_cb, found)
|
self._call_cb(result_cb, found, self.text, self._flags, 'next_result')
|
||||||
|
|
||||||
def prev_result(self, *, result_cb=None):
|
def prev_result(self, *, result_cb=None):
|
||||||
|
self.search_displayed = True
|
||||||
# The int() here makes sure we get a copy of the flags.
|
# The int() here makes sure we get a copy of the flags.
|
||||||
flags = QWebPage.FindFlags(int(self._flags))
|
flags = QWebPage.FindFlags(int(self._flags))
|
||||||
if flags & QWebPage.FindBackward:
|
if flags & QWebPage.FindBackward:
|
||||||
@ -150,7 +173,7 @@ class WebKitSearch(browsertab.AbstractSearch):
|
|||||||
else:
|
else:
|
||||||
flags |= QWebPage.FindBackward
|
flags |= QWebPage.FindBackward
|
||||||
found = self._widget.findText(self.text, flags)
|
found = self._widget.findText(self.text, flags)
|
||||||
self._call_cb(result_cb, found)
|
self._call_cb(result_cb, found, self.text, flags, 'prev_result')
|
||||||
|
|
||||||
|
|
||||||
class WebKitCaret(browsertab.AbstractCaret):
|
class WebKitCaret(browsertab.AbstractCaret):
|
||||||
@ -444,15 +467,11 @@ class WebKitScroller(browsertab.AbstractScroller):
|
|||||||
# self._widget.setFocus()
|
# self._widget.setFocus()
|
||||||
|
|
||||||
for _ in range(min(count, 5000)):
|
for _ in range(min(count, 5000)):
|
||||||
press_evt = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier, 0, 0, 0)
|
|
||||||
release_evt = QKeyEvent(QEvent.KeyRelease, key, Qt.NoModifier,
|
|
||||||
0, 0, 0)
|
|
||||||
# Abort scrolling if the minimum/maximum was reached.
|
# Abort scrolling if the minimum/maximum was reached.
|
||||||
if (getter is not None and
|
if (getter is not None and
|
||||||
frame.scrollBarValue(direction) == getter(direction)):
|
frame.scrollBarValue(direction) == getter(direction)):
|
||||||
return
|
return
|
||||||
self._widget.keyPressEvent(press_evt)
|
self._tab.key_press(key)
|
||||||
self._widget.keyReleaseEvent(release_evt)
|
|
||||||
|
|
||||||
def up(self, count=1):
|
def up(self, count=1):
|
||||||
self._key_press(Qt.Key_Up, count, 'scrollBarMinimum', Qt.Vertical)
|
self._key_press(Qt.Key_Up, count, 'scrollBarMinimum', Qt.Vertical)
|
||||||
@ -678,6 +697,13 @@ class WebKitTab(browsertab.AbstractTab):
|
|||||||
def clear_ssl_errors(self):
|
def clear_ssl_errors(self):
|
||||||
self.networkaccessmanager().clear_all_ssl_errors()
|
self.networkaccessmanager().clear_all_ssl_errors()
|
||||||
|
|
||||||
|
def key_press(self, key, modifier=Qt.NoModifier):
|
||||||
|
press_evt = QKeyEvent(QEvent.KeyPress, key, modifier, 0, 0, 0)
|
||||||
|
release_evt = QKeyEvent(QEvent.KeyRelease, key, modifier,
|
||||||
|
0, 0, 0)
|
||||||
|
self.send_event(press_evt)
|
||||||
|
self.send_event(release_evt)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _on_history_trigger(self):
|
def _on_history_trigger(self):
|
||||||
url = self.url()
|
url = self.url()
|
||||||
@ -707,6 +733,9 @@ class WebKitTab(browsertab.AbstractTab):
|
|||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _on_webkit_icon_changed(self):
|
def _on_webkit_icon_changed(self):
|
||||||
"""Emit iconChanged with a QIcon like QWebEngineView does."""
|
"""Emit iconChanged with a QIcon like QWebEngineView does."""
|
||||||
|
if sip.isdeleted(self._widget):
|
||||||
|
log.webview.debug("Got _on_webkit_icon_changed for deleted view!")
|
||||||
|
return
|
||||||
self.icon_changed.emit(self._widget.icon())
|
self.icon_changed.emit(self._widget.icon())
|
||||||
|
|
||||||
@pyqtSlot(QWebFrame)
|
@pyqtSlot(QWebFrame)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -140,7 +140,7 @@ class WebView(QWebView):
|
|||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def add_js_bridge(self):
|
def add_js_bridge(self):
|
||||||
"""Add the javascript bridge for qute:... pages."""
|
"""Add the javascript bridge for qute://... pages."""
|
||||||
frame = self.sender()
|
frame = self.sender()
|
||||||
if not isinstance(frame, QWebFrame):
|
if not isinstance(frame, QWebFrame):
|
||||||
log.webview.error("Got non-QWebFrame {!r} in "
|
log.webview.error("Got non-QWebFrame {!r} in "
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -76,11 +76,11 @@ class ArgumentParser(argparse.ArgumentParser):
|
|||||||
self.name = name
|
self.name = name
|
||||||
super().__init__(*args, add_help=False, prog=name, **kwargs)
|
super().__init__(*args, add_help=False, prog=name, **kwargs)
|
||||||
|
|
||||||
def exit(self, status=0, msg=None):
|
def exit(self, status=0, message=None):
|
||||||
raise ArgumentParserExit(status, msg)
|
raise ArgumentParserExit(status, message)
|
||||||
|
|
||||||
def error(self, msg):
|
def error(self, message):
|
||||||
raise ArgumentParserError(msg.capitalize())
|
raise ArgumentParserError(message.capitalize())
|
||||||
|
|
||||||
|
|
||||||
def arg_name(name):
|
def arg_name(name):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -133,7 +133,8 @@ class CommandRunner(QObject):
|
|||||||
Yields:
|
Yields:
|
||||||
ParseResult tuples.
|
ParseResult tuples.
|
||||||
"""
|
"""
|
||||||
if not text.strip():
|
text = text.strip().lstrip(':').strip()
|
||||||
|
if not text:
|
||||||
raise cmdexc.NoSuchCommandError("No command given")
|
raise cmdexc.NoSuchCommandError("No command given")
|
||||||
|
|
||||||
if aliases:
|
if aliases:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -23,7 +23,7 @@ Defines a CompletionView which uses CompletionFiterModel and CompletionModel
|
|||||||
subclasses to provide completions.
|
subclasses to provide completions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QStyle, QTreeView, QSizePolicy
|
from PyQt5.QtWidgets import QStyle, QTreeView, QSizePolicy, QStyleFactory
|
||||||
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QItemSelectionModel, QSize
|
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QItemSelectionModel, QSize
|
||||||
|
|
||||||
from qutebrowser.config import config, style
|
from qutebrowser.config import config, style
|
||||||
@ -117,6 +117,7 @@ class CompletionView(QTreeView):
|
|||||||
|
|
||||||
self._delegate = completiondelegate.CompletionItemDelegate(self)
|
self._delegate = completiondelegate.CompletionItemDelegate(self)
|
||||||
self.setItemDelegate(self._delegate)
|
self.setItemDelegate(self._delegate)
|
||||||
|
self.setStyle(QStyleFactory.create('Fusion'))
|
||||||
style.set_register_stylesheet(self)
|
style.set_register_stylesheet(self)
|
||||||
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||||
self.setHeaderHidden(True)
|
self.setHeaderHidden(True)
|
||||||
@ -124,6 +125,7 @@ class CompletionView(QTreeView):
|
|||||||
self.setIndentation(0)
|
self.setIndentation(0)
|
||||||
self.setItemsExpandable(False)
|
self.setItemsExpandable(False)
|
||||||
self.setExpandsOnDoubleClick(False)
|
self.setExpandsOnDoubleClick(False)
|
||||||
|
self.setAnimated(False)
|
||||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||||
# WORKAROUND
|
# WORKAROUND
|
||||||
# This is a workaround for weird race conditions with invalid
|
# This is a workaround for weird race conditions with invalid
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||||
|
|
||||||
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
#
|
#
|
||||||
# This file is part of qutebrowser.
|
# This file is part of qutebrowser.
|
||||||
#
|
#
|
||||||
@ -103,7 +103,7 @@ class BaseCompletionModel(QStandardItemModel):
|
|||||||
nameitem.setData(userdata, Role.userdata)
|
nameitem.setData(userdata, Role.userdata)
|
||||||
return nameitem, descitem, miscitem
|
return nameitem, descitem, miscitem
|
||||||
|
|
||||||
def delete_cur_item(self, win_id):
|
def delete_cur_item(self, completion):
|
||||||
"""Delete the selected item."""
|
"""Delete the selected item."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|