Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 32028a54b9 | |||
| b6aa3083d2 | |||
| 0c55fdc44b | |||
| 750456642c | |||
| 27dbc9085d | |||
| 7b0d7f8807 | |||
| bbedaf73de | |||
| 6040b1633d | |||
| 1ddd589cc2 | |||
| 5e81d90c1f | |||
| 46a49f1b90 | |||
| 3772e696ce | |||
| f9d10d37ec | |||
| 4a082ab8ee | |||
| fcc570d75f | |||
| 7732d95626 | |||
| fc0922c661 |
@@ -1,4 +1,4 @@
|
|||||||
#  KrowLog
|
#  KrowLog
|
||||||
|
|
||||||
KrowLog is a viewer for text files of arbitrary size.
|
KrowLog is a viewer for text files of arbitrary size.
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
0.2-alpha
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
krow_icon = "icons/icon.png"
|
krow_icon = "icons/krowlog.svg"
|
||||||
|
|
||||||
tab_width = 4
|
tab_width = 4
|
||||||
|
|||||||
46
icons/krowlog.svg
Normal file
46
icons/krowlog.svg
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="64" height="64" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="bg1" x1="0%" y1="100%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" style="stop-color:#9f8700"/>
|
||||||
|
<stop offset="100%" style="stop-color:#ffdb00"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="fg1" x1="0%" y1="100%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" style="stop-color:#8caec7"/>
|
||||||
|
<stop offset="100%" style="stop-color:#6289a3"/>
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient id="rg1">
|
||||||
|
<stop offset="0%" stop-color="white"/>
|
||||||
|
<stop offset="100%" stop-color="black"/>
|
||||||
|
</radialGradient>
|
||||||
|
</defs>
|
||||||
|
<rect x="8" y="8" width="112" height="112" style="fill:url(#fg1)" rx="10"/>
|
||||||
|
<path style="fill:black"
|
||||||
|
d="M76,113
|
||||||
|
L15,113
|
||||||
|
L15,70
|
||||||
|
C15,70 25,55 45,36
|
||||||
|
C53,29 60,26 78,32
|
||||||
|
C85,34 90,32 90,32
|
||||||
|
C95,30 108,35 110,40
|
||||||
|
L110,40
|
||||||
|
C83,48 80,60 76,71
|
||||||
|
C74,80 76,113 76,113
|
||||||
|
z"/>
|
||||||
|
<rect x="8" y="8" width="112" height="112"
|
||||||
|
style="fill:none; stroke:url(#bg1); stroke-width:14" rx="10"/>
|
||||||
|
|
||||||
|
<circle cx="65" cy="40" r="6" fill="url(#rg1)"/>
|
||||||
|
<circle cx="65" cy="40" r="3" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -1,16 +1,15 @@
|
|||||||
import logging
|
import logging
|
||||||
import signal
|
import signal
|
||||||
|
|
||||||
from PySide6 import QtCore
|
from PySide6 import QtCore
|
||||||
from PySide6.QtWidgets import QApplication
|
from PySide6.QtWidgets import QApplication
|
||||||
from PySide6.QtCore import QTimer
|
from PySide6.QtCore import QTimer
|
||||||
from PySide6.QtGui import QIcon
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import constants
|
import constants
|
||||||
from src.pluginregistry import PluginRegistry
|
from src.pluginregistry import PluginRegistry
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
|
from src.ui.icon import Icon
|
||||||
|
|
||||||
|
__version__ = '0.2.0'
|
||||||
|
|
||||||
gettext.install('krowlog', 'locale')
|
gettext.install('krowlog', 'locale')
|
||||||
|
|
||||||
@@ -31,7 +30,7 @@ def stop_signal(signum, _stackframe):
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
app.setWindowIcon(QIcon(constants.krow_icon)) # works only for Linux
|
app.setWindowIcon(Icon(constants.krow_icon)) # works only for Linux
|
||||||
|
|
||||||
# make icon appear in Windows
|
# make icon appear in Windows
|
||||||
# see https://stackoverflow.com/questions/1551605/how-to-set-applications-taskbar-icon-in-windows-7/1552105#1552105
|
# see https://stackoverflow.com/questions/1551605/how-to-set-applications-taskbar-icon-in-windows-7/1552105#1552105
|
||||||
Binary file not shown.
@@ -5,8 +5,8 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: RavenLog\n"
|
"Project-Id-Version: RavenLog\n"
|
||||||
"POT-Creation-Date: 2022-08-23 20:08+0200\n"
|
"POT-Creation-Date: 2022-08-25 19:21+0200\n"
|
||||||
"PO-Revision-Date: 2022-08-23 20:09+0200\n"
|
"PO-Revision-Date: 2022-08-25 19:23+0200\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Language: de\n"
|
"Language: de\n"
|
||||||
@@ -54,30 +54,30 @@ msgstr "&Suchtreffer Hervorheben"
|
|||||||
msgid "Open Tab on Save As File"
|
msgid "Open Tab on Save As File"
|
||||||
msgstr "Öffne neues Tab wenn Selektion als neue Datei gespeichert wird"
|
msgstr "Öffne neues Tab wenn Selektion als neue Datei gespeichert wird"
|
||||||
|
|
||||||
#: src/plugins/filesbrowserplugin.py:35
|
#: src/plugins/filesbrowser/filesbrowserwidget.py:37
|
||||||
msgid "&Files Browser"
|
|
||||||
msgstr "&Dateibrowser"
|
|
||||||
|
|
||||||
#: src/plugins/filesbrowserplugin.py:41
|
|
||||||
msgid "Files Browser"
|
|
||||||
msgstr "Dateibrowser"
|
|
||||||
|
|
||||||
#: src/plugins/findInFiles/filesbrowserwidget.py:37
|
|
||||||
msgid "Focus on current file"
|
msgid "Focus on current file"
|
||||||
msgstr "Auf aktuelle Datei fokussieren"
|
msgstr "Auf aktuelle Datei fokussieren"
|
||||||
|
|
||||||
#: src/plugins/findInFiles/filesbrowserwidget.py:40
|
#: src/plugins/filesbrowser/filesbrowserwidget.py:40
|
||||||
msgid "Folder:"
|
msgid "Folder:"
|
||||||
msgstr "Ordner:"
|
msgstr "Ordner:"
|
||||||
|
|
||||||
#: src/plugins/findInFiles/filesbrowserwidget.py:45
|
#: src/plugins/filesbrowser/filesbrowserwidget.py:45
|
||||||
msgid "Filter:"
|
msgid "Filter:"
|
||||||
msgstr "Filter:"
|
msgstr "Filter:"
|
||||||
|
|
||||||
#: src/plugins/findInFiles/filesbrowserwidget.py:73
|
#: src/plugins/filesbrowser/filesbrowserwidget.py:73
|
||||||
msgid "Open Directory"
|
msgid "Open Directory"
|
||||||
msgstr "Ordner öffnen"
|
msgstr "Ordner öffnen"
|
||||||
|
|
||||||
|
#: src/plugins/filesbrowserplugin.py:30
|
||||||
|
msgid "&Files Browser"
|
||||||
|
msgstr "&Dateibrowser"
|
||||||
|
|
||||||
|
#: src/plugins/filesbrowserplugin.py:36
|
||||||
|
msgid "Files Browser"
|
||||||
|
msgstr "Dateibrowser"
|
||||||
|
|
||||||
#: src/plugins/krowlog/aboutdialog.py:19
|
#: src/plugins/krowlog/aboutdialog.py:19
|
||||||
msgid "About KrowLog"
|
msgid "About KrowLog"
|
||||||
msgstr "Über KrowLog"
|
msgstr "Über KrowLog"
|
||||||
@@ -146,22 +146,26 @@ msgstr "&Über KrowLog"
|
|||||||
msgid "E&xit"
|
msgid "E&xit"
|
||||||
msgstr "&Beenden"
|
msgstr "&Beenden"
|
||||||
|
|
||||||
#: src/plugins/logfile/filterwidget.py:137
|
#: src/plugins/logfile/filterwidget.py:149
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Abbrechen"
|
msgstr "Abbrechen"
|
||||||
|
|
||||||
#: src/plugins/logfile/filterwidget.py:143
|
#: src/plugins/logfile/filterwidget.py:155
|
||||||
msgid "save query"
|
msgid "save query"
|
||||||
msgstr "suche speichern"
|
msgstr "suche speichern"
|
||||||
|
|
||||||
#: src/plugins/logfile/filterwidget.py:148
|
#: src/plugins/logfile/filterwidget.py:160
|
||||||
msgid "ignore case"
|
msgid "ignore case"
|
||||||
msgstr "Groß-/Kleinschreibung ignorieren"
|
msgstr "Groß-/Kleinschreibung ignorieren"
|
||||||
|
|
||||||
#: src/plugins/logfile/filterwidget.py:152
|
#: src/plugins/logfile/filterwidget.py:164
|
||||||
msgid "regex"
|
msgid "regex"
|
||||||
msgstr "RegExp"
|
msgstr "RegExp"
|
||||||
|
|
||||||
|
#: src/plugins/logfile/filterwidget.py:251
|
||||||
|
msgid "({hits} lines)"
|
||||||
|
msgstr "({hits} Zeilen)"
|
||||||
|
|
||||||
#: src/plugins/logfileplugin.py:26
|
#: src/plugins/logfileplugin.py:26
|
||||||
msgid "File not found"
|
msgid "File not found"
|
||||||
msgstr "Datei nicht gefunden"
|
msgstr "Datei nicht gefunden"
|
||||||
@@ -312,11 +316,11 @@ msgstr "Echtes Blau"
|
|||||||
|
|
||||||
#: src/ui/colorbutton.py:33
|
#: src/ui/colorbutton.py:33
|
||||||
msgid "Fairy Topia"
|
msgid "Fairy Topia"
|
||||||
msgstr ""
|
msgstr "Fairy Topia"
|
||||||
|
|
||||||
#: src/ui/colorbutton.py:34
|
#: src/ui/colorbutton.py:34
|
||||||
msgid "Magenta Bachiego"
|
msgid "Magenta Bachiego"
|
||||||
msgstr ""
|
msgstr "Magenta Bachiego"
|
||||||
|
|
||||||
#: src/ui/colorbutton.py:36
|
#: src/ui/colorbutton.py:36
|
||||||
msgid "Breeze of Mist"
|
msgid "Breeze of Mist"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"POT-Creation-Date: 2022-08-23 20:08+0200\n"
|
"POT-Creation-Date: 2022-08-25 19:21+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -52,30 +52,30 @@ msgstr ""
|
|||||||
msgid "Open Tab on Save As File"
|
msgid "Open Tab on Save As File"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/plugins/filesbrowserplugin.py:35
|
#: src/plugins/filesbrowser/filesbrowserwidget.py:37
|
||||||
msgid "&Files Browser"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/plugins/filesbrowserplugin.py:41
|
|
||||||
msgid "Files Browser"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/plugins/findInFiles/filesbrowserwidget.py:37
|
|
||||||
msgid "Focus on current file"
|
msgid "Focus on current file"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/plugins/findInFiles/filesbrowserwidget.py:40
|
#: src/plugins/filesbrowser/filesbrowserwidget.py:40
|
||||||
msgid "Folder:"
|
msgid "Folder:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/plugins/findInFiles/filesbrowserwidget.py:45
|
#: src/plugins/filesbrowser/filesbrowserwidget.py:45
|
||||||
msgid "Filter:"
|
msgid "Filter:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/plugins/findInFiles/filesbrowserwidget.py:73
|
#: src/plugins/filesbrowser/filesbrowserwidget.py:73
|
||||||
msgid "Open Directory"
|
msgid "Open Directory"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/plugins/filesbrowserplugin.py:30
|
||||||
|
msgid "&Files Browser"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/plugins/filesbrowserplugin.py:36
|
||||||
|
msgid "Files Browser"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/plugins/krowlog/aboutdialog.py:19
|
#: src/plugins/krowlog/aboutdialog.py:19
|
||||||
msgid "About KrowLog"
|
msgid "About KrowLog"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -140,22 +140,26 @@ msgstr ""
|
|||||||
msgid "E&xit"
|
msgid "E&xit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/plugins/logfile/filterwidget.py:137
|
#: src/plugins/logfile/filterwidget.py:149
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/plugins/logfile/filterwidget.py:143
|
#: src/plugins/logfile/filterwidget.py:155
|
||||||
msgid "save query"
|
msgid "save query"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/plugins/logfile/filterwidget.py:148
|
#: src/plugins/logfile/filterwidget.py:160
|
||||||
msgid "ignore case"
|
msgid "ignore case"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/plugins/logfile/filterwidget.py:152
|
#: src/plugins/logfile/filterwidget.py:164
|
||||||
msgid "regex"
|
msgid "regex"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/plugins/logfile/filterwidget.py:251
|
||||||
|
msgid "({hits} lines)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/plugins/logfileplugin.py:26
|
#: src/plugins/logfileplugin.py:26
|
||||||
msgid "File not found"
|
msgid "File not found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
pip==22.2.2
|
pip==22.2.2
|
||||||
PySide6==6.3.1
|
PySide6-Essentials==6.3.1
|
||||||
setuptools==62.1.0
|
setuptools==65.3.0
|
||||||
urllib3==1.26.11
|
urllib3==1.26.12
|
||||||
watchdog==2.1.9
|
watchdog==2.1.9
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
from abc import abstractmethod
|
|
||||||
|
|
||||||
|
|
||||||
class PluginBase():
|
class PluginBase():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"""
|
"""
|
||||||
Subclasses that use state must implement this method and return a new instance of themselves.
|
Subclasses that use state must implement this method and return a new instance of themselves.
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ from typing import Callable
|
|||||||
from PySide6.QtGui import QAction, QIcon
|
from PySide6.QtGui import QAction, QIcon
|
||||||
from PySide6.QtWidgets import QMenu, QPushButton, QWidget
|
from PySide6.QtWidgets import QMenu, QPushButton, QWidget
|
||||||
|
|
||||||
|
from src.ui.icon import Icon
|
||||||
|
|
||||||
|
|
||||||
class RAction():
|
class RAction():
|
||||||
|
|
||||||
@@ -65,9 +67,9 @@ class RAction():
|
|||||||
def _update_check_state(self):
|
def _update_check_state(self):
|
||||||
if self._action:
|
if self._action:
|
||||||
if self.checked:
|
if self.checked:
|
||||||
self._action.setIcon(QIcon("icons/ionicons/checkbox-outline.svg"))
|
self._action.setIcon(Icon("icons/ionicons/checkbox-outline.svg"))
|
||||||
else:
|
else:
|
||||||
self._action.setIcon(QIcon("icons/ionicons/square-outline.svg"))
|
self._action.setIcon(Icon("icons/ionicons/square-outline.svg"))
|
||||||
|
|
||||||
def set_label(self, label: str):
|
def set_label(self, label: str):
|
||||||
if self._action:
|
if self._action:
|
||||||
@@ -77,9 +79,9 @@ class RAction():
|
|||||||
action = QAction(self.label, qmenu)
|
action = QAction(self.label, qmenu)
|
||||||
self._action = action
|
self._action = action
|
||||||
if self.icon_from_theme:
|
if self.icon_from_theme:
|
||||||
action.setIcon(QIcon.fromTheme(self.icon_from_theme))
|
action.setIcon(Icon.fromTheme(self.icon_from_theme))
|
||||||
if self.icon_file:
|
if self.icon_file:
|
||||||
action.setIcon(QIcon(self.icon_file))
|
action.setIcon(Icon(self.icon_file))
|
||||||
if self.shortcut:
|
if self.shortcut:
|
||||||
action.setShortcut(self.shortcut)
|
action.setShortcut(self.shortcut)
|
||||||
if self.action:
|
if self.action:
|
||||||
@@ -95,9 +97,9 @@ class RAction():
|
|||||||
if self.label:
|
if self.label:
|
||||||
button.setText(self.label)
|
button.setText(self.label)
|
||||||
if self.icon_from_theme:
|
if self.icon_from_theme:
|
||||||
button.setIcon(QIcon.fromTheme(self.icon_from_theme))
|
button.setIcon(Icon.fromTheme(self.icon_from_theme))
|
||||||
if self.icon_file:
|
if self.icon_file:
|
||||||
button.setIcon(QIcon(self.icon_file))
|
button.setIcon(Icon(self.icon_file))
|
||||||
if self.shortcut:
|
if self.shortcut:
|
||||||
button.setShortcut(self.shortcut)
|
button.setShortcut(self.shortcut)
|
||||||
if self.action:
|
if self.action:
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
from abc import ABC
|
|
||||||
|
|
||||||
from PySide6.QtCore import Qt
|
from PySide6.QtCore import Qt
|
||||||
|
|
||||||
from src.pluginbase import PluginBase
|
from src.pluginbase import PluginBase
|
||||||
from src.pluginregistry import PluginRegistry
|
from src.pluginregistry import PluginRegistry
|
||||||
from src.plugins.domain.menucontribution import MenuContribution
|
from src.plugins.domain.menucontribution import MenuContribution
|
||||||
from src.plugins.domain.raction import RAction
|
from src.plugins.domain.raction import RAction
|
||||||
from src.plugins.findInFiles.filesbrowserwidget import FilesBrowserWidget
|
from src.plugins.filesbrowser.filesbrowserwidget import FilesBrowserWidget
|
||||||
from src.i18n import _
|
from src.i18n import _
|
||||||
from src.settings.settings import Settings
|
from src.settings.settings import Settings
|
||||||
|
|
||||||
@@ -17,9 +15,6 @@ class FilesBrowserPlugin(PluginBase):
|
|||||||
super(FilesBrowserPlugin, self).__init__()
|
super(FilesBrowserPlugin, self).__init__()
|
||||||
self.settings = None
|
self.settings = None
|
||||||
|
|
||||||
def copy(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def set_settings(self, settings: Settings):
|
def set_settings(self, settings: Settings):
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
if not self.settings.session.has_section("filesBrowser"):
|
if not self.settings.session.has_section("filesBrowser"):
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
import PySide6
|
import PySide6
|
||||||
|
import urllib3
|
||||||
|
from watchdog import version as watchdog_version
|
||||||
from PySide6.QtCore import Qt
|
from PySide6.QtCore import Qt
|
||||||
from PySide6.QtGui import QFont, QPixmap
|
from PySide6.QtGui import QFont
|
||||||
from PySide6.QtWidgets import *
|
from PySide6.QtWidgets import *
|
||||||
|
|
||||||
import constants
|
import constants
|
||||||
|
|
||||||
|
import krowlog
|
||||||
|
from src.ui.icon import Icon
|
||||||
from src.ui.label import Label
|
from src.ui.label import Label
|
||||||
from src.ui.vbox import VBox
|
from src.ui.vbox import VBox
|
||||||
from src.i18n import _
|
from src.i18n import _
|
||||||
@@ -21,16 +26,16 @@ class AboutDialog(QDialog):
|
|||||||
|
|
||||||
self.layout = QVBoxLayout(self)
|
self.layout = QVBoxLayout(self)
|
||||||
|
|
||||||
heading_app_name = QLabel(_("KrowLog"))
|
heading_app_name = Label(_("KrowLog"))
|
||||||
heading_app_name.setAlignment(Qt.AlignmentFlag.AlignLeft)
|
heading_app_name.setAlignment(Qt.AlignmentFlag.AlignLeft)
|
||||||
heading_app_name.setFont(QFont("default", 25))
|
heading_app_name.setFont(QFont("default", 25))
|
||||||
heading_app_name.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
|
# heading_app_name.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
|
||||||
|
|
||||||
version = QLabel(_("Version: {0}").format(self._version()))
|
version = Label(_("Version: {0}").format(krowlog.__version__))
|
||||||
version.setAlignment(Qt.AlignmentFlag.AlignLeft)
|
version.setAlignment(Qt.AlignmentFlag.AlignLeft)
|
||||||
|
|
||||||
app_icon = QLabel()
|
app_icon = QLabel()
|
||||||
app_icon.setPixmap(QPixmap(constants.krow_icon))
|
app_icon.setPixmap(Icon(constants.krow_icon).pixmap(64, 64))
|
||||||
heading = QWidget(self)
|
heading = QWidget(self)
|
||||||
hbox = QHBoxLayout(heading)
|
hbox = QHBoxLayout(heading)
|
||||||
hbox.addWidget(app_icon)
|
hbox.addWidget(app_icon)
|
||||||
@@ -66,21 +71,18 @@ class AboutDialog(QDialog):
|
|||||||
dependencies = """
|
dependencies = """
|
||||||
<ul>
|
<ul>
|
||||||
<li>Ionicons (MIT) - <a href="https://github.com/ionic-team/ionicons">https://github.com/ionic-team/ionicons</a></li>
|
<li>Ionicons (MIT) - <a href="https://github.com/ionic-team/ionicons">https://github.com/ionic-team/ionicons</a></li>
|
||||||
<li>PySide6 {pyside} (LGPL v3) - <a href="https://doc.qt.io/qtforpython-6/">https://doc.qt.io/qtforpython-6/</a></li>
|
<li>PySide6-Essentials {pyside} (LGPL v3) - <a href="https://doc.qt.io/qtforpython-6/">https://doc.qt.io/qtforpython-6/</a></li>
|
||||||
<li>Qt6 {qt} (LGPL v3) - <a href="https://code.qt.io/cgit/qt/qtbase.git/">https://code.qt.io/cgit/qt/qtbase.git/</a></li>
|
<li>Qt6 {qt} (LGPL v3) - <a href="https://code.qt.io/cgit/qt/qtbase.git/">https://code.qt.io/cgit/qt/qtbase.git/</a></li>
|
||||||
<li>urllib3 (MIT) - <a href="https://github.com/urllib3/urllib3">https://github.com/urllib3/urllib3</a></li>
|
<li>urllib3 {urllib3} (MIT) - <a href="https://github.com/urllib3/urllib3">https://github.com/urllib3/urllib3</a></li>
|
||||||
<li>watchdog 2.16 (Apache 2.0) - <a href="https://github.com/gorakhargosh/watchdog">https://github.com/gorakhargosh/watchdog</a></li>
|
<li>watchdog {watchdog} (Apache 2.0) - <a href="https://github.com/gorakhargosh/watchdog">https://github.com/gorakhargosh/watchdog</a></li>
|
||||||
</ul>""".format(pyside=PySide6.__version__, qt=PySide6.QtCore.__version__)
|
</ul>""".format(
|
||||||
|
pyside=PySide6.__version__,
|
||||||
|
qt=PySide6.QtCore.__version__,
|
||||||
|
urllib3=urllib3.__version__,
|
||||||
|
watchdog=watchdog_version.VERSION_STRING)
|
||||||
label = textwrap.dedent(dependencies)
|
label = textwrap.dedent(dependencies)
|
||||||
|
|
||||||
result = QWidget()
|
result = QWidget()
|
||||||
result.layout = QVBoxLayout(result)
|
result.layout = QVBoxLayout(result)
|
||||||
result.layout.addWidget(Label(label))
|
result.layout.addWidget(Label(label))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _version(self):
|
|
||||||
with open('VERSION.info', "rt") as f:
|
|
||||||
line = f.readline()
|
|
||||||
version = line.strip()
|
|
||||||
return version
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from typing import Optional, Callable
|
|||||||
from PySide6.QtCore import QRunnable, QThreadPool, Signal
|
from PySide6.QtCore import QRunnable, QThreadPool, Signal
|
||||||
from PySide6.QtGui import QIcon
|
from PySide6.QtGui import QIcon
|
||||||
from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QCheckBox, QPushButton, QComboBox, \
|
from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QCheckBox, QPushButton, QComboBox, \
|
||||||
QSizePolicy, QProgressBar, QMenu, QMenuBar
|
QSizePolicy, QProgressBar
|
||||||
|
|
||||||
from src.plugins.domain.raction import RAction
|
from src.plugins.domain.raction import RAction
|
||||||
from src.plugins.logfile.preprocesslineshook import PreProcessLinesHook
|
from src.plugins.logfile.preprocesslineshook import PreProcessLinesHook
|
||||||
@@ -18,6 +18,8 @@ from src.ui.bigtext.logFileModel import LogFileModel
|
|||||||
from src.i18n import _
|
from src.i18n import _
|
||||||
from src.pluginregistry import PluginRegistry
|
from src.pluginregistry import PluginRegistry
|
||||||
from src.ui.hbox import HBox
|
from src.ui.hbox import HBox
|
||||||
|
from src.ui.icon import Icon
|
||||||
|
from src.ui.label import Label
|
||||||
from src.zonedpluginregistry import ZonedPluginRegistry
|
from src.zonedpluginregistry import ZonedPluginRegistry
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ class FilterTask(QRunnable):
|
|||||||
filter_match_found_listeners: Callable[[int], None],
|
filter_match_found_listeners: Callable[[int], None],
|
||||||
pre_process_lines_hooks: [PreProcessLinesHook],
|
pre_process_lines_hooks: [PreProcessLinesHook],
|
||||||
progress_handler: Callable[[float], None],
|
progress_handler: Callable[[float], None],
|
||||||
|
update_hits_handler: Callable[[int], None],
|
||||||
on_before: Callable[[], None],
|
on_before: Callable[[], None],
|
||||||
on_finish: Callable[[], None]
|
on_finish: Callable[[], None]
|
||||||
):
|
):
|
||||||
@@ -41,6 +44,7 @@ class FilterTask(QRunnable):
|
|||||||
self.filter_model = filter_model
|
self.filter_model = filter_model
|
||||||
self.regex = regex
|
self.regex = regex
|
||||||
self.progress_handler = progress_handler
|
self.progress_handler = progress_handler
|
||||||
|
self.update_hits_handler = update_hits_handler
|
||||||
self.pre_process_lines_hooks = pre_process_lines_hooks
|
self.pre_process_lines_hooks = pre_process_lines_hooks
|
||||||
self.on_before = on_before
|
self.on_before = on_before
|
||||||
self.on_finish = on_finish
|
self.on_finish = on_finish
|
||||||
@@ -61,19 +65,20 @@ class FilterTask(QRunnable):
|
|||||||
for listener in self.filter_match_found_listeners:
|
for listener in self.filter_match_found_listeners:
|
||||||
listener(-1, -1) # notify listeners that a new search started
|
listener(-1, -1) # notify listeners that a new search started
|
||||||
|
|
||||||
|
hits_count = 0
|
||||||
last_progress_report = time.time()
|
last_progress_report = time.time()
|
||||||
try:
|
try:
|
||||||
with open(self.source_model.get_file(), "rb") as source:
|
with open(self.source_model.get_file(), "rb") as source:
|
||||||
with open(self.filter_model.get_file(), "w+b") as target:
|
with open(self.filter_model.get_file(), "w+b") as target:
|
||||||
line_count = 0
|
line_count = 0
|
||||||
lines_written = 0
|
lines_written = 0
|
||||||
while l := source.readline():
|
while line_encoded := source.readline():
|
||||||
line_count = line_count + 1
|
line_count = line_count + 1
|
||||||
line = l.decode("utf8", errors="ignore")
|
line = line_encoded.decode("utf8", errors="ignore")
|
||||||
|
|
||||||
if self.regex.findall(line):
|
if self.regex.findall(line):
|
||||||
lines_written = lines_written + 1
|
lines_written = lines_written + 1
|
||||||
source_line_offset = source.tell() - len(l)
|
source_line_offset = source.tell() - len(line_encoded)
|
||||||
target_line_offset = target.tell()
|
target_line_offset = target.tell()
|
||||||
for listener in self.filter_match_found_listeners:
|
for listener in self.filter_match_found_listeners:
|
||||||
listener(target_line_offset, source_line_offset)
|
listener(target_line_offset, source_line_offset)
|
||||||
@@ -83,6 +88,7 @@ class FilterTask(QRunnable):
|
|||||||
line = h.pre_process_line(line, target)
|
line = h.pre_process_line(line, target)
|
||||||
|
|
||||||
target.write(line.encode("utf8"))
|
target.write(line.encode("utf8"))
|
||||||
|
hits_count = hits_count + 1
|
||||||
|
|
||||||
# sometime buffering can hide results for a while
|
# sometime buffering can hide results for a while
|
||||||
# We force a flush periodically.
|
# We force a flush periodically.
|
||||||
@@ -95,12 +101,15 @@ class FilterTask(QRunnable):
|
|||||||
if now - last_progress_report > 0.2:
|
if now - last_progress_report > 0.2:
|
||||||
progress = source.tell() / os.stat(self.source_model.get_file()).st_size
|
progress = source.tell() / os.stat(self.source_model.get_file()).st_size
|
||||||
self.progress_handler(progress)
|
self.progress_handler(progress)
|
||||||
|
self.update_hits_handler(hits_count)
|
||||||
last_progress_report = now
|
last_progress_report = now
|
||||||
|
|
||||||
if self.aborted:
|
if self.aborted:
|
||||||
|
self.update_hits_handler(hits_count)
|
||||||
# print("aborted ", time.time())
|
# print("aborted ", time.time())
|
||||||
break
|
break
|
||||||
finally:
|
finally:
|
||||||
|
self.update_hits_handler(hits_count)
|
||||||
self.on_finish()
|
self.on_finish()
|
||||||
# print("dome thread ", threading.currentThread())
|
# print("dome thread ", threading.currentThread())
|
||||||
|
|
||||||
@@ -110,6 +119,7 @@ class FilterWidget(QWidget):
|
|||||||
filter_task: Optional[FilterTask] = None
|
filter_task: Optional[FilterTask] = None
|
||||||
search_is_running = Signal(bool)
|
search_is_running = Signal(bool)
|
||||||
signal_update_progress = Signal(float)
|
signal_update_progress = Signal(float)
|
||||||
|
signal_update_hits = Signal(int)
|
||||||
|
|
||||||
def __init__(self, source_model: LogFileModel, zoned_plugin_registry: ZonedPluginRegistry):
|
def __init__(self, source_model: LogFileModel, zoned_plugin_registry: ZonedPluginRegistry):
|
||||||
super(FilterWidget, self).__init__()
|
super(FilterWidget, self).__init__()
|
||||||
@@ -129,6 +139,9 @@ class FilterWidget(QWidget):
|
|||||||
self.query_field.lineEdit().returnPressed.connect(self.filter_changed)
|
self.query_field.lineEdit().returnPressed.connect(self.filter_changed)
|
||||||
self.query_field.setInsertPolicy(QComboBox.NoInsert)
|
self.query_field.setInsertPolicy(QComboBox.NoInsert)
|
||||||
|
|
||||||
|
self.hits_field = Label("")
|
||||||
|
self.signal_update_hits.connect(self._update_hits)
|
||||||
|
|
||||||
self.progress_bar = QProgressBar()
|
self.progress_bar = QProgressBar()
|
||||||
self.progress_bar.setVisible(False)
|
self.progress_bar.setVisible(False)
|
||||||
self.progress_bar.setMaximumWidth(50)
|
self.progress_bar.setMaximumWidth(50)
|
||||||
@@ -139,7 +152,7 @@ class FilterWidget(QWidget):
|
|||||||
self.btn_cancel_search.pressed.connect(self._cancel_search)
|
self.btn_cancel_search.pressed.connect(self._cancel_search)
|
||||||
self.search_is_running.connect(self.search_running_status_changed)
|
self.search_is_running.connect(self.search_running_status_changed)
|
||||||
|
|
||||||
self.btn_bookmark = QPushButton(QIcon("icons/ionicons/star.svg"), "")
|
self.btn_bookmark = QPushButton(Icon("icons/ionicons/star.svg"), "")
|
||||||
self.btn_bookmark.setToolTip(_("save query"))
|
self.btn_bookmark.setToolTip(_("save query"))
|
||||||
self.btn_bookmark.pressed.connect(self._save_query)
|
self.btn_bookmark.pressed.connect(self._save_query)
|
||||||
|
|
||||||
@@ -157,16 +170,17 @@ class FilterWidget(QWidget):
|
|||||||
filter_bar.layout = QHBoxLayout(filter_bar)
|
filter_bar.layout = QHBoxLayout(filter_bar)
|
||||||
filter_bar.layout.setContentsMargins(0, 0, 0, 0)
|
filter_bar.layout.setContentsMargins(0, 0, 0, 0)
|
||||||
filter_bar.layout.addWidget(self.query_field)
|
filter_bar.layout.addWidget(self.query_field)
|
||||||
|
filter_bar.layout.addWidget(self.btn_bookmark)
|
||||||
|
filter_bar.layout.addWidget(self.hits_field)
|
||||||
filter_bar.layout.addWidget(self.progress_bar)
|
filter_bar.layout.addWidget(self.progress_bar)
|
||||||
filter_bar.layout.addWidget(self.btn_cancel_search)
|
filter_bar.layout.addWidget(self.btn_cancel_search)
|
||||||
filter_bar.layout.addWidget(self.btn_bookmark)
|
|
||||||
filter_bar.layout.addWidget(self.menu)
|
filter_bar.layout.addWidget(self.menu)
|
||||||
filter_bar.layout.addWidget(self.ignore_case)
|
filter_bar.layout.addWidget(self.ignore_case)
|
||||||
filter_bar.layout.addWidget(self.is_regex)
|
filter_bar.layout.addWidget(self.is_regex)
|
||||||
|
|
||||||
(handle, self.tmpfilename) = tempfile.mkstemp()
|
(handle, self.tmp_filename) = tempfile.mkstemp()
|
||||||
os.close(handle)
|
os.close(handle)
|
||||||
self.filter_model = LogFileModel(self.tmpfilename, self.source_model.settings)
|
self.filter_model = LogFileModel(self.tmp_filename, self.source_model.settings)
|
||||||
self.hits_view = BigText(self.filter_model)
|
self.hits_view = BigText(self.filter_model)
|
||||||
|
|
||||||
self.layout.addWidget(filter_bar)
|
self.layout.addWidget(filter_bar)
|
||||||
@@ -208,9 +222,8 @@ class FilterWidget(QWidget):
|
|||||||
self._reload_save_queries()
|
self._reload_save_queries()
|
||||||
|
|
||||||
def destruct(self):
|
def destruct(self):
|
||||||
# print("cleanup: ", self.tmpfilename)
|
|
||||||
self._cancel_search()
|
self._cancel_search()
|
||||||
os.remove(self.tmpfilename)
|
os.remove(self.tmp_filename)
|
||||||
|
|
||||||
def _cancel_search(self):
|
def _cancel_search(self):
|
||||||
if self.filter_task:
|
if self.filter_task:
|
||||||
@@ -224,6 +237,7 @@ class FilterWidget(QWidget):
|
|||||||
self.filter_model.truncate()
|
self.filter_model.truncate()
|
||||||
self.source_model.clear_query_highlight()
|
self.source_model.clear_query_highlight()
|
||||||
self.filter_model.clear_query_highlight()
|
self.filter_model.clear_query_highlight()
|
||||||
|
self._update_hits(-1)
|
||||||
PluginRegistry.execute("update_ui")
|
PluginRegistry.execute("update_ui")
|
||||||
|
|
||||||
def search_running_status_changed(self, is_running: bool):
|
def search_running_status_changed(self, is_running: bool):
|
||||||
@@ -233,9 +247,18 @@ class FilterWidget(QWidget):
|
|||||||
def update_progress(self, progress: float):
|
def update_progress(self, progress: float):
|
||||||
self.progress_bar.setValue(progress * 100)
|
self.progress_bar.setValue(progress * 100)
|
||||||
|
|
||||||
|
def _update_hits(self, hits: int):
|
||||||
|
if hits >= 0:
|
||||||
|
self.hits_field.setText(_("({hits} lines)").format(hits=hits))
|
||||||
|
else:
|
||||||
|
self.hits_field.setText("")
|
||||||
|
|
||||||
def progress_handler(self, progress: float):
|
def progress_handler(self, progress: float):
|
||||||
self.signal_update_progress.emit(progress)
|
self.signal_update_progress.emit(progress)
|
||||||
|
|
||||||
|
def update_hits_handler(self, hits: int):
|
||||||
|
self.signal_update_hits.emit(hits)
|
||||||
|
|
||||||
def filter_changed(self):
|
def filter_changed(self):
|
||||||
query = self.query_field.currentText()
|
query = self.query_field.currentText()
|
||||||
ignore_case = self.ignore_case.isChecked()
|
ignore_case = self.ignore_case.isChecked()
|
||||||
@@ -260,6 +283,7 @@ class FilterWidget(QWidget):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.progress_bar.setValue(0)
|
self.progress_bar.setValue(0)
|
||||||
|
self._update_hits(-1)
|
||||||
|
|
||||||
self.source_model.set_query_highlight(query, ignore_case, is_regex)
|
self.source_model.set_query_highlight(query, ignore_case, is_regex)
|
||||||
self.filter_model.set_query_highlight(query, ignore_case, is_regex)
|
self.filter_model.set_query_highlight(query, ignore_case, is_regex)
|
||||||
@@ -274,6 +298,7 @@ class FilterWidget(QWidget):
|
|||||||
self.filter_match_found_listeners,
|
self.filter_match_found_listeners,
|
||||||
pre_process_lines_hooks,
|
pre_process_lines_hooks,
|
||||||
self.progress_handler,
|
self.progress_handler,
|
||||||
|
self.update_hits_handler,
|
||||||
lambda: self.search_is_running.emit(True),
|
lambda: self.search_is_running.emit(True),
|
||||||
lambda: self.search_is_running.emit(False)
|
lambda: self.search_is_running.emit(False)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import sys
|
|
||||||
|
|
||||||
import math
|
import math
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
@@ -12,6 +10,7 @@ from PySide6.QtGui import QMouseEvent
|
|||||||
from PySide6.QtWidgets import *
|
from PySide6.QtWidgets import *
|
||||||
|
|
||||||
from src.ui.ScaledScrollBar import ScaledScrollBar
|
from src.ui.ScaledScrollBar import ScaledScrollBar
|
||||||
|
from src.ui.bigtext.highlight_regex import HighlightRegex
|
||||||
from src.ui.bigtext.highlight_selection import HighlightSelection
|
from src.ui.bigtext.highlight_selection import HighlightSelection
|
||||||
from src.ui.bigtext.highlighted_range import HighlightedRange
|
from src.ui.bigtext.highlighted_range import HighlightedRange
|
||||||
from src.ui.bigtext.highlightingdialog import HighlightingDialog
|
from src.ui.bigtext.highlightingdialog import HighlightingDialog
|
||||||
@@ -97,7 +96,6 @@ class BigText(QWidget):
|
|||||||
|
|
||||||
def add_line_click_listener(self, listener: Callable[[int], None]):
|
def add_line_click_listener(self, listener: Callable[[int], None]):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
:param listener: a callable, the parameter is the byte offset of the clicked line
|
:param listener: a callable, the parameter is the byte offset of the clicked line
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
@@ -111,6 +109,7 @@ class BigText(QWidget):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyArgumentList,PyTypeChecker
|
||||||
class InnerBigText(QWidget):
|
class InnerBigText(QWidget):
|
||||||
_byte_offset = 0
|
_byte_offset = 0
|
||||||
_left_offset = 0
|
_left_offset = 0
|
||||||
@@ -119,6 +118,8 @@ class InnerBigText(QWidget):
|
|||||||
|
|
||||||
def __init__(self, parent: BigText, model: LogFileModel):
|
def __init__(self, parent: BigText, model: LogFileModel):
|
||||||
super(InnerBigText, self).__init__()
|
super(InnerBigText, self).__init__()
|
||||||
|
self.char_height = None
|
||||||
|
self.char_width = None
|
||||||
self.model = model
|
self.model = model
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||||
@@ -132,6 +133,12 @@ class InnerBigText(QWidget):
|
|||||||
self._last_double_click_time = 0
|
self._last_double_click_time = 0
|
||||||
self._last_double_click_line_number = -1
|
self._last_double_click_line_number = -1
|
||||||
|
|
||||||
|
self.highlight_selected_text = HighlightRegex(
|
||||||
|
"",
|
||||||
|
is_regex=False,
|
||||||
|
ignore_case=True,
|
||||||
|
hit_background_color="d7efffc0") # same blue as the selection hightlight, but with lower saturation
|
||||||
|
|
||||||
self.line_click_listeners: [Callable[[int], None]] = []
|
self.line_click_listeners: [Callable[[int], None]] = []
|
||||||
|
|
||||||
def keyPressEvent(self, e: QKeyEvent) -> None:
|
def keyPressEvent(self, e: QKeyEvent) -> None:
|
||||||
@@ -203,10 +210,12 @@ class InnerBigText(QWidget):
|
|||||||
self.update()
|
self.update()
|
||||||
self.parent.v_scroll_bar.setValue(self._byte_offset)
|
self.parent.v_scroll_bar.setValue(self._byte_offset)
|
||||||
|
|
||||||
|
# noinspection PyTypeChecker
|
||||||
def mousePressEvent(self, e: QtGui.QMouseEvent) -> None:
|
def mousePressEvent(self, e: QtGui.QMouseEvent) -> None:
|
||||||
if e.buttons() == Qt.MouseButton.LeftButton and e.modifiers() == Qt.KeyboardModifier.ShiftModifier:
|
if e.buttons() == Qt.MouseButton.LeftButton and e.modifiers() == Qt.KeyboardModifier.ShiftModifier:
|
||||||
offset = self.to_byte_offset(e)
|
offset = self.to_byte_offset(e)
|
||||||
self.selection_highlight.set_end_byte(offset)
|
self.selection_highlight.set_end_byte(offset)
|
||||||
|
self._update_highlight_selected_text()
|
||||||
self.update()
|
self.update()
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -217,6 +226,7 @@ class InnerBigText(QWidget):
|
|||||||
line: Line = self.lines[line_number]
|
line: Line = self.lines[line_number]
|
||||||
self.selection_highlight.set_start(line.byte_offset())
|
self.selection_highlight.set_start(line.byte_offset())
|
||||||
self.selection_highlight.set_end_byte(line.byte_end())
|
self.selection_highlight.set_end_byte(line.byte_end())
|
||||||
|
self._update_highlight_selected_text()
|
||||||
self.update()
|
self.update()
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -224,6 +234,7 @@ class InnerBigText(QWidget):
|
|||||||
offset = self.to_byte_offset(e)
|
offset = self.to_byte_offset(e)
|
||||||
self.selection_highlight.set_start(offset)
|
self.selection_highlight.set_start(offset)
|
||||||
self.selection_highlight.set_end_byte(offset)
|
self.selection_highlight.set_end_byte(offset)
|
||||||
|
self._update_highlight_selected_text()
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
line_number = self.y_pos_to_line(e.pos().y())
|
line_number = self.y_pos_to_line(e.pos().y())
|
||||||
@@ -245,6 +256,8 @@ class InnerBigText(QWidget):
|
|||||||
else:
|
else:
|
||||||
self.selection_highlight.set_start(offset)
|
self.selection_highlight.set_start(offset)
|
||||||
self.selection_highlight.set_end_byte(offset)
|
self.selection_highlight.set_end_byte(offset)
|
||||||
|
|
||||||
|
self._update_highlight_selected_text()
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def mouseMoveEvent(self, e: QMouseEvent):
|
def mouseMoveEvent(self, e: QMouseEvent):
|
||||||
@@ -256,8 +269,10 @@ class InnerBigText(QWidget):
|
|||||||
|
|
||||||
if self.selection_highlight.end_byte != current_byte:
|
if self.selection_highlight.end_byte != current_byte:
|
||||||
self.selection_highlight.set_end_byte(current_byte)
|
self.selection_highlight.set_end_byte(current_byte)
|
||||||
|
self._update_highlight_selected_text()
|
||||||
self.update()
|
self.update()
|
||||||
# print("-> %s,%s" %(self._selection_start_byte, self._selection_end_byte))
|
# print("-> %s,%s" %(self._selection_start_byte, self._selection_end_byte))
|
||||||
|
|
||||||
line_number = self.y_pos_to_line(e.pos().y())
|
line_number = self.y_pos_to_line(e.pos().y())
|
||||||
column_in_line = self.x_pos_to_column(e.pos().x())
|
column_in_line = self.x_pos_to_column(e.pos().x())
|
||||||
if line_number < 0:
|
if line_number < 0:
|
||||||
@@ -310,7 +325,7 @@ class InnerBigText(QWidget):
|
|||||||
column_in_line = self.x_pos_to_column(e.pos().x()) + self._left_offset
|
column_in_line = self.x_pos_to_column(e.pos().x()) + self._left_offset
|
||||||
column_in_line = min(column_in_line, line.length_in_columns()) # x was behind the last column of this line
|
column_in_line = min(column_in_line, line.length_in_columns()) # x was behind the last column of this line
|
||||||
char_in_line = line.column_to_char(column_in_line)
|
char_in_line = line.column_to_char(column_in_line)
|
||||||
# print("%s in line %s lcolumn_in_line=%s" % (char_in_line, line_number, column_in_line))
|
# print("%s in line %s column_in_line=%s" % (char_in_line, line_number, column_in_line))
|
||||||
byte_in_line = line.char_index_to_byte(char_in_line)
|
byte_in_line = line.char_index_to_byte(char_in_line)
|
||||||
current_byte = line.byte_offset() + byte_in_line
|
current_byte = line.byte_offset() + byte_in_line
|
||||||
# print("%s + %s = %s" % (line.byte_offset(), char_in_line, current_byte))
|
# print("%s + %s = %s" % (line.byte_offset(), char_in_line, current_byte))
|
||||||
@@ -332,6 +347,7 @@ class InnerBigText(QWidget):
|
|||||||
_("data selection"),
|
_("data selection"),
|
||||||
_(
|
_(
|
||||||
"You have selected <b>{0}</b> of data.").format(bytes_human_readable))
|
"You have selected <b>{0}</b> of data.").format(bytes_human_readable))
|
||||||
|
# noinspection PyTypeChecker
|
||||||
you_sure.setStandardButtons(QMessageBox.Cancel)
|
you_sure.setStandardButtons(QMessageBox.Cancel)
|
||||||
copy_btn = you_sure.addButton(_("Copy {0} to Clipboard").format(bytes_human_readable),
|
copy_btn = you_sure.addButton(_("Copy {0} to Clipboard").format(bytes_human_readable),
|
||||||
QMessageBox.ActionRole)
|
QMessageBox.ActionRole)
|
||||||
@@ -357,6 +373,7 @@ class InnerBigText(QWidget):
|
|||||||
end = max(self.selection_highlight.start_byte, self.selection_highlight.end_byte)
|
end = max(self.selection_highlight.start_byte, self.selection_highlight.end_byte)
|
||||||
dialog = QFileDialog(self)
|
dialog = QFileDialog(self)
|
||||||
(selected_file, _filter) = dialog.getSaveFileName(
|
(selected_file, _filter) = dialog.getSaveFileName(
|
||||||
|
parent=self,
|
||||||
caption=_("Save File"),
|
caption=_("Save File"),
|
||||||
dir=os.path.dirname(self.model.get_file())
|
dir=os.path.dirname(self.model.get_file())
|
||||||
)
|
)
|
||||||
@@ -369,19 +386,28 @@ class InnerBigText(QWidget):
|
|||||||
def _select_all(self):
|
def _select_all(self):
|
||||||
self.selection_highlight.start_byte = 0
|
self.selection_highlight.start_byte = 0
|
||||||
self.selection_highlight.end_byte = self.model.byte_count()
|
self.selection_highlight.end_byte = self.model.byte_count()
|
||||||
|
self._update_highlight_selected_text()
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
def _update_highlight_selected_text(self):
|
||||||
|
start_byte=self.selection_highlight.start_byte
|
||||||
|
end_byte=self.selection_highlight.end_byte
|
||||||
|
if abs(start_byte - end_byte) < 1024:
|
||||||
|
query = self.model.read_range(start_byte, end_byte)
|
||||||
|
if query.find("\n") < 0:
|
||||||
|
self.highlight_selected_text.set_query(query)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.highlight_selected_text.set_query("")
|
||||||
|
|
||||||
def paintEvent(self, event: QPaintEvent) -> None:
|
def paintEvent(self, event: QPaintEvent) -> None:
|
||||||
# print("paintEvent %s" % (self.model.get_file()))
|
|
||||||
painter = QPainter(self)
|
painter = QPainter(self)
|
||||||
# painter.setFont(self.model.settings.font())
|
# font = "Courier New" if sys.platform == 'win32' or sys.platform == 'cygwin' else "Monospace"
|
||||||
# Courier New, DejaVu Sans Mono, Monospace, Liberation Mono, Noto Mono, Nimbus Mono L, Tlwg Mono, Ubuntu Mono, FreeMono, Mitra Mono
|
|
||||||
font = "Courier New" if sys.platform == 'win32' or sys.platform == 'cygwin' else "Monospace"
|
|
||||||
painter.setFont(QFont("Courier New", self.model.settings.getint_session('general', "font_size")))
|
painter.setFont(QFont("Courier New", self.model.settings.getint_session('general', "font_size")))
|
||||||
painter.setPen(QColor(0, 0, 0))
|
painter.setPen(QColor(0, 0, 0))
|
||||||
self.update_font_metrics(painter)
|
self.update_font_metrics(painter)
|
||||||
|
|
||||||
lines_to_show = self.lines_shown()
|
lines_to_show = math.ceil(self.lines_shown())
|
||||||
# print("%s / %s = %s" %(self.height(), float(self.char_height), lines_to_show))
|
# print("%s / %s = %s" %(self.height(), float(self.char_height), lines_to_show))
|
||||||
|
|
||||||
self.lines = self.model.data(self._byte_offset, self.scroll_lines, lines_to_show)
|
self.lines = self.model.data(self._byte_offset, self.scroll_lines, lines_to_show)
|
||||||
@@ -392,36 +418,33 @@ class InnerBigText(QWidget):
|
|||||||
# document length == maximum + pageStep + aFewBytesSoThatTheLastLineIsShown
|
# document length == maximum + pageStep + aFewBytesSoThatTheLastLineIsShown
|
||||||
self.parent.v_scroll_bar.setMaximum(self.model.byte_count() - 1)
|
self.parent.v_scroll_bar.setMaximum(self.model.byte_count() - 1)
|
||||||
|
|
||||||
for l in self.lines:
|
for line in self.lines:
|
||||||
self.update_longest_line(len(l.line()))
|
self.update_longest_line(len(line.line()))
|
||||||
|
|
||||||
highlighters = self.model.highlighters()
|
highlighters = self.model.highlighters()
|
||||||
if self.model.get_query_highlight():
|
if self.model.get_query_highlight():
|
||||||
highlighters = highlighters + [self.model.get_query_highlight()]
|
highlighters = highlighters + [self.model.get_query_highlight()]
|
||||||
|
highlighters = highlighters + [self.highlight_selected_text]
|
||||||
highlighters = highlighters + [self.selection_highlight] # selection highlight should be last
|
highlighters = highlighters + [self.selection_highlight] # selection highlight should be last
|
||||||
|
|
||||||
# draw hightlights first - some characters may overlap to the next line
|
# draw highlights first - some characters may overlap to the next line
|
||||||
# by drawing the background hightlights first we prevent that the hightlight
|
# by drawing the background highlights first we prevent that the highlight
|
||||||
# draws over a character
|
# draws over a character
|
||||||
start = time.time()
|
y_line_offset = self.char_height
|
||||||
y_line_offset = self.char_height;
|
for line in self.lines:
|
||||||
for l in self.lines:
|
|
||||||
highlight_ranges = []
|
highlight_ranges = []
|
||||||
for h in highlighters:
|
for h in highlighters:
|
||||||
optional_highlight_range = h.compute_highlight(l)
|
optional_highlight_range = h.compute_highlight(line)
|
||||||
if optional_highlight_range:
|
if optional_highlight_range:
|
||||||
highlight_ranges = highlight_ranges + optional_highlight_range
|
highlight_ranges = highlight_ranges + optional_highlight_range
|
||||||
|
|
||||||
self.draw_highlights(highlight_ranges, painter, y_line_offset)
|
self.draw_highlights(highlight_ranges, painter, y_line_offset)
|
||||||
y_line_offset = y_line_offset + self.char_height
|
y_line_offset = y_line_offset + self.char_height
|
||||||
|
|
||||||
end = time.time()
|
|
||||||
# print("highlight duration: %.3f" %((end-start)*1000))
|
|
||||||
|
|
||||||
left_offset = int(-1 * self._left_offset * self.char_width)
|
left_offset = int(-1 * self._left_offset * self.char_width)
|
||||||
y_line_offset = self.char_height;
|
y_line_offset = self.char_height
|
||||||
for l in self.lines:
|
for line in self.lines:
|
||||||
text = l.line_prepared_for_display()
|
text = line.line_prepared_for_display()
|
||||||
painter.drawText(left_offset, y_line_offset, text)
|
painter.drawText(left_offset, y_line_offset, text)
|
||||||
y_line_offset = y_line_offset + self.char_height
|
y_line_offset = y_line_offset + self.char_height
|
||||||
|
|
||||||
@@ -461,6 +484,6 @@ class InnerBigText(QWidget):
|
|||||||
fm: QFontMetrics = painter.fontMetrics()
|
fm: QFontMetrics = painter.fontMetrics()
|
||||||
self.char_height = fm.height()
|
self.char_height = fm.height()
|
||||||
self.char_width = fm.averageCharWidth() # all chars have same width for monospace font
|
self.char_width = fm.averageCharWidth() # all chars have same width for monospace font
|
||||||
text = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
text = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012"
|
||||||
self.char_width = fm.horizontalAdvance(text) / float(len(text))
|
self.char_width = fm.horizontalAdvance(text) / float(len(text))
|
||||||
# print("font width=%s height=%s" % (self.char_width, self.char_height))
|
# print("font width=%s height=%s" % (self.char_width, self.char_height))
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ class HighlightRegex(Highlight):
|
|||||||
else:
|
else:
|
||||||
return re.compile(re.escape(self.query), flags=flags)
|
return re.compile(re.escape(self.query), flags=flags)
|
||||||
|
|
||||||
|
def set_query(self, query: str) -> None:
|
||||||
|
self.query = query
|
||||||
|
self.regex = self._get_regex()
|
||||||
|
|
||||||
def compute_highlight(self, line: Line) -> Optional[List[HighlightedRange]]:
|
def compute_highlight(self, line: Line) -> Optional[List[HighlightedRange]]:
|
||||||
result = []
|
result = []
|
||||||
# print("execute regex: %s in %s" % (self.regex, line.line()))
|
# print("execute regex: %s in %s" % (self.regex, line.line()))
|
||||||
@@ -56,9 +60,15 @@ class HighlightRegex(Highlight):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def brush(color: str) -> QBrush:
|
def brush(color: str) -> QBrush:
|
||||||
if re.match("[0-9a-f]{6}", color, flags=re.IGNORECASE):
|
if re.match("^[0-9a-f]{6}$", color, flags=re.IGNORECASE):
|
||||||
red = int(color[0:2], 16)
|
red = int(color[0:2], 16)
|
||||||
green = int(color[2:4], 16)
|
green = int(color[2:4], 16)
|
||||||
blue = int(color[4:6], 16)
|
blue = int(color[4:6], 16)
|
||||||
return QBrush(QColor(red, green, blue))
|
return QBrush(QColor(red, green, blue))
|
||||||
|
if re.match("^[0-9a-f]{8}$", color, flags=re.IGNORECASE):
|
||||||
|
red = int(color[0:2], 16)
|
||||||
|
green = int(color[2:4], 16)
|
||||||
|
blue = int(color[4:6], 16)
|
||||||
|
alpha = int(color[6:8], 16)
|
||||||
|
return QBrush(QColor(red, green, blue, alpha))
|
||||||
return QBrush()
|
return QBrush()
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
from PySide6.QtGui import QIcon
|
|
||||||
from PySide6.QtWidgets import QDialog, QLineEdit, QLabel, QGridLayout, QCheckBox, QListWidget, QListWidgetItem, \
|
from PySide6.QtWidgets import QDialog, QLineEdit, QLabel, QGridLayout, QCheckBox, QListWidget, QListWidgetItem, \
|
||||||
QPushButton, QDialogButtonBox, QMessageBox, QSizePolicy
|
QPushButton, QDialogButtonBox, QMessageBox, QSizePolicy
|
||||||
|
|
||||||
@@ -9,6 +8,7 @@ from src.ui.hbox import HBox
|
|||||||
from src.settings.settings import Settings
|
from src.settings.settings import Settings
|
||||||
|
|
||||||
from src.i18n import _
|
from src.i18n import _
|
||||||
|
from src.ui.icon import Icon
|
||||||
|
|
||||||
|
|
||||||
class PayloadItem(QListWidgetItem):
|
class PayloadItem(QListWidgetItem):
|
||||||
@@ -32,23 +32,23 @@ class HighlightingDialog(QDialog):
|
|||||||
form_grid.addWidget(self.list, row, 0, 1, 2)
|
form_grid.addWidget(self.list, row, 0, 1, 2)
|
||||||
|
|
||||||
row = row + 1
|
row = row + 1
|
||||||
self.btn_add = QPushButton(QIcon.fromTheme("list-add"), _("Add"))
|
self.btn_add = QPushButton(Icon.fromTheme("list-add"), _("Add"))
|
||||||
self.btn_add.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
|
self.btn_add.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
|
||||||
self.btn_add.pressed.connect(self._add)
|
self.btn_add.pressed.connect(self._add)
|
||||||
|
|
||||||
self.btn_update = QPushButton(QIcon.fromTheme("stock_edit"), _("Update"))
|
self.btn_update = QPushButton(Icon.fromTheme("stock_edit"), _("Update"))
|
||||||
self.btn_update.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
|
self.btn_update.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
|
||||||
self.btn_update.pressed.connect(self._update)
|
self.btn_update.pressed.connect(self._update)
|
||||||
|
|
||||||
self.btn_delete = QPushButton(QIcon.fromTheme("list-remove"), _("Remove"))
|
self.btn_delete = QPushButton(Icon.fromTheme("list-remove"), _("Remove"))
|
||||||
self.btn_delete.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
|
self.btn_delete.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
|
||||||
self.btn_delete.pressed.connect(self._delete)
|
self.btn_delete.pressed.connect(self._delete)
|
||||||
|
|
||||||
self.btn_move_up = QPushButton(QIcon.fromTheme("go-up"), _("Up"))
|
self.btn_move_up = QPushButton(Icon.fromTheme("go-up"), _("Up"))
|
||||||
self.btn_move_up.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
|
self.btn_move_up.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
|
||||||
self.btn_move_up.pressed.connect(self._move_up)
|
self.btn_move_up.pressed.connect(self._move_up)
|
||||||
|
|
||||||
self.btn_move_down = QPushButton(QIcon.fromTheme("go-down"), _("Down"))
|
self.btn_move_down = QPushButton(Icon.fromTheme("go-down"), _("Down"))
|
||||||
self.btn_move_down.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
|
self.btn_move_down.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed))
|
||||||
self.btn_move_down.pressed.connect(self._move_down)
|
self.btn_move_down.pressed.connect(self._move_down)
|
||||||
button_box = HBox(self.btn_update, self.btn_add, self.btn_delete, self.btn_move_up, self.btn_move_down)
|
button_box = HBox(self.btn_update, self.btn_add, self.btn_delete, self.btn_move_up, self.btn_move_down)
|
||||||
|
|||||||
11
src/ui/icon.py
Normal file
11
src/ui/icon.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from PySide6.QtGui import QIcon
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class Icon(QIcon):
|
||||||
|
def __init__(self, file_name: str):
|
||||||
|
super(Icon, self).__init__("%s" % Path(__file__).parent.parent.parent.joinpath(file_name).absolute())
|
||||||
|
print("%s -> %s" % (file_name, Path(__file__).parent.parent.parent.joinpath(file_name).absolute()))
|
||||||
|
|
||||||
|
def fromTheme(icon_from_theme: str) -> QIcon:
|
||||||
|
return QIcon.fromTheme(icon_from_theme)
|
||||||
@@ -11,9 +11,12 @@ def urls_to_path(urls: str) -> [str]:
|
|||||||
result.append(path)
|
result.append(path)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def url_to_path(url: str) -> str:
|
def url_to_path(url: str) -> str:
|
||||||
p = urlparse(url)
|
p = urlparse(url)
|
||||||
if sys.platform == 'win32' or sys.platform == 'cygwin':
|
if sys.platform == 'win32' or sys.platform == 'cygwin':
|
||||||
|
if p.netloc:
|
||||||
|
return f"//{p.netloc}{p.path}"
|
||||||
return os.path.abspath(p.path[1:])
|
return os.path.abspath(p.path[1:])
|
||||||
return os.path.abspath(os.path.join(p.netloc, p.path))
|
return os.path.abspath(os.path.join(p.netloc, p.path))
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
import sys
|
|
||||||
|
|
||||||
from PyQt6.QtWidgets import QApplication, QMainWindow, QDockWidget, QLabel, QTextEdit
|
|
||||||
from PyQt6.QtCore import Qt
|
|
||||||
|
|
||||||
|
|
||||||
class DockWindow(QMainWindow):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(DockWindow, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
self.dock_1 = QDockWidget("Dock1", self)
|
|
||||||
self.dock_1.layout().addWidget(QLabel("dock1"))
|
|
||||||
|
|
||||||
self.dock_2 = QDockWidget("Dock2", self)
|
|
||||||
self.dock_2.layout().addWidget(QLabel("dock2"))
|
|
||||||
|
|
||||||
self.dock_3 = QDockWidget("Dock3", self)
|
|
||||||
self.dock_3.layout().addWidget(QLabel("dock3"))
|
|
||||||
|
|
||||||
self.setCentralWidget(QTextEdit())
|
|
||||||
self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.dock_1)
|
|
||||||
self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.dock_2)
|
|
||||||
self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.dock_3)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
|
|
||||||
window = DockWindow()
|
|
||||||
window.show()
|
|
||||||
|
|
||||||
app.exec()
|
|
||||||
Reference in New Issue
Block a user