Aaaargh, CRLFs
This commit is contained in:
parent
f2223064b3
commit
7a549b38a4
@ -1,171 +1,171 @@
|
||||
import logging
|
||||
from collections import OrderedDict
|
||||
|
||||
from PyQt5.QtCore import (QAbstractItemModel, Qt, QModelIndex, QVariant,
|
||||
QSortFilterProxyModel, pyqtSignal)
|
||||
|
||||
class CompletionModel(QAbstractItemModel):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self._data = OrderedDict()
|
||||
self.parents = []
|
||||
self.root = CompletionItem([""] * 2)
|
||||
|
||||
def removeRows(self, position=0, count=1, parent=QModelIndex()):
|
||||
node = self.node(parent)
|
||||
self.beginRemoveRows(parent, position, position + count - 1)
|
||||
node.childItems.pop(position)
|
||||
self.endRemoveRows()
|
||||
|
||||
def node(self, index):
|
||||
if index.isValid():
|
||||
return index.internalPointer()
|
||||
else:
|
||||
return self.root
|
||||
|
||||
def columnCount(self, parent=QModelIndex()):
|
||||
return self.root.column_count()
|
||||
|
||||
def data(self, index, role=Qt.DisplayRole):
|
||||
if not index.isValid():
|
||||
return QVariant()
|
||||
item = index.internalPointer()
|
||||
try:
|
||||
return QVariant(item.data(index.column(), role))
|
||||
except (IndexError, ValueError):
|
||||
return QVariant()
|
||||
|
||||
def flags(self, index):
|
||||
# FIXME categories are not selectable, but moving via arrow keys still
|
||||
# tries to select them
|
||||
if not index.isValid():
|
||||
return Qt.NoItemFlags
|
||||
flags = Qt.ItemIsEnabled
|
||||
if len(index.internalPointer().children) > 0:
|
||||
return flags
|
||||
else:
|
||||
return flags | Qt.ItemIsSelectable
|
||||
|
||||
def headerData(self, section, orientation, role=Qt.DisplayRole):
|
||||
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
|
||||
return QVariant(self.root.data(section))
|
||||
return None
|
||||
|
||||
def setData(self, index, value, role=Qt.EditRole):
|
||||
if not index.isValid():
|
||||
return False
|
||||
item = index.internalPointer()
|
||||
try:
|
||||
item.setdata(index.column(), value, role)
|
||||
except (IndexError, ValueError):
|
||||
return False
|
||||
self.dataChanged.emit(index, index)
|
||||
return True
|
||||
|
||||
def index(self, row, column, parent=QModelIndex()):
|
||||
if (0 <= row < self.rowCount(parent) and
|
||||
0 <= column < self.columnCount(parent)):
|
||||
pass
|
||||
else:
|
||||
return QModelIndex()
|
||||
|
||||
if not parent.isValid():
|
||||
parent_item = self.root
|
||||
else:
|
||||
parent_item = parent.internalPointer()
|
||||
|
||||
child_item = parent_item.children[row]
|
||||
if child_item:
|
||||
return self.createIndex(row, column, child_item)
|
||||
else:
|
||||
return QModelIndex()
|
||||
|
||||
def parent(self, index):
|
||||
if not index.isValid():
|
||||
return QModelIndex()
|
||||
item = index.internalPointer().parent
|
||||
if item == self.root or item is None:
|
||||
return QModelIndex()
|
||||
return self.createIndex(item.row(), 0, item)
|
||||
|
||||
def rowCount(self, parent=QModelIndex()):
|
||||
if parent.column() > 0:
|
||||
return 0
|
||||
|
||||
if not parent.isValid():
|
||||
pitem = self.root
|
||||
else:
|
||||
pitem = parent.internalPointer()
|
||||
|
||||
return len(pitem.children)
|
||||
|
||||
def init_data(self):
|
||||
for (cat, items) in self._data.items():
|
||||
newcat = CompletionItem([cat], self.root)
|
||||
self.root.children.append(newcat)
|
||||
for item in items:
|
||||
newitem = CompletionItem(item, newcat)
|
||||
newcat.children.append(newitem)
|
||||
|
||||
class CompletionItem():
|
||||
parent = None
|
||||
_data = None
|
||||
children = None
|
||||
_marks = None
|
||||
|
||||
def __init__(self, data, parent=None):
|
||||
self.parent = parent
|
||||
self._data = data
|
||||
self.children = []
|
||||
self._marks = []
|
||||
|
||||
def data(self, column, role=Qt.DisplayRole):
|
||||
if role == Qt.DisplayRole:
|
||||
return self._data[column]
|
||||
elif role == Qt.UserRole:
|
||||
return self._marks
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
def setdata(self, column, value, role=Qt.DisplayRole):
|
||||
if role == Qt.DisplayRole:
|
||||
self._data[column] = value
|
||||
elif role == Qt.UserRole:
|
||||
self._marks = value
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
def column_count(self):
|
||||
return len(self._data)
|
||||
|
||||
def row(self):
|
||||
if self.parent:
|
||||
return self.parent.children.index(self)
|
||||
return 0
|
||||
|
||||
class CompletionFilterModel(QSortFilterProxyModel):
|
||||
_pattern = None
|
||||
# FIXME sort in a way strings starting with pattern are first
|
||||
|
||||
@property
|
||||
def pattern(self):
|
||||
return self._pattern
|
||||
|
||||
@pattern.setter
|
||||
def pattern(self, val):
|
||||
self._pattern = val
|
||||
self.invalidateFilter()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.pattern = ''
|
||||
|
||||
def filterAcceptsRow(self, row, parent):
|
||||
if parent == QModelIndex():
|
||||
return True
|
||||
idx = self.sourceModel().index(row, 0, parent);
|
||||
data = self.sourceModel().data(idx).value()
|
||||
# TODO more sophisticated filtering
|
||||
if not self.pattern:
|
||||
return True
|
||||
return self.pattern in data
|
||||
import logging
|
||||
from collections import OrderedDict
|
||||
|
||||
from PyQt5.QtCore import (QAbstractItemModel, Qt, QModelIndex, QVariant,
|
||||
QSortFilterProxyModel, pyqtSignal)
|
||||
|
||||
class CompletionModel(QAbstractItemModel):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self._data = OrderedDict()
|
||||
self.parents = []
|
||||
self.root = CompletionItem([""] * 2)
|
||||
|
||||
def removeRows(self, position=0, count=1, parent=QModelIndex()):
|
||||
node = self.node(parent)
|
||||
self.beginRemoveRows(parent, position, position + count - 1)
|
||||
node.childItems.pop(position)
|
||||
self.endRemoveRows()
|
||||
|
||||
def node(self, index):
|
||||
if index.isValid():
|
||||
return index.internalPointer()
|
||||
else:
|
||||
return self.root
|
||||
|
||||
def columnCount(self, parent=QModelIndex()):
|
||||
return self.root.column_count()
|
||||
|
||||
def data(self, index, role=Qt.DisplayRole):
|
||||
if not index.isValid():
|
||||
return QVariant()
|
||||
item = index.internalPointer()
|
||||
try:
|
||||
return QVariant(item.data(index.column(), role))
|
||||
except (IndexError, ValueError):
|
||||
return QVariant()
|
||||
|
||||
def flags(self, index):
|
||||
# FIXME categories are not selectable, but moving via arrow keys still
|
||||
# tries to select them
|
||||
if not index.isValid():
|
||||
return Qt.NoItemFlags
|
||||
flags = Qt.ItemIsEnabled
|
||||
if len(index.internalPointer().children) > 0:
|
||||
return flags
|
||||
else:
|
||||
return flags | Qt.ItemIsSelectable
|
||||
|
||||
def headerData(self, section, orientation, role=Qt.DisplayRole):
|
||||
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
|
||||
return QVariant(self.root.data(section))
|
||||
return None
|
||||
|
||||
def setData(self, index, value, role=Qt.EditRole):
|
||||
if not index.isValid():
|
||||
return False
|
||||
item = index.internalPointer()
|
||||
try:
|
||||
item.setdata(index.column(), value, role)
|
||||
except (IndexError, ValueError):
|
||||
return False
|
||||
self.dataChanged.emit(index, index)
|
||||
return True
|
||||
|
||||
def index(self, row, column, parent=QModelIndex()):
|
||||
if (0 <= row < self.rowCount(parent) and
|
||||
0 <= column < self.columnCount(parent)):
|
||||
pass
|
||||
else:
|
||||
return QModelIndex()
|
||||
|
||||
if not parent.isValid():
|
||||
parent_item = self.root
|
||||
else:
|
||||
parent_item = parent.internalPointer()
|
||||
|
||||
child_item = parent_item.children[row]
|
||||
if child_item:
|
||||
return self.createIndex(row, column, child_item)
|
||||
else:
|
||||
return QModelIndex()
|
||||
|
||||
def parent(self, index):
|
||||
if not index.isValid():
|
||||
return QModelIndex()
|
||||
item = index.internalPointer().parent
|
||||
if item == self.root or item is None:
|
||||
return QModelIndex()
|
||||
return self.createIndex(item.row(), 0, item)
|
||||
|
||||
def rowCount(self, parent=QModelIndex()):
|
||||
if parent.column() > 0:
|
||||
return 0
|
||||
|
||||
if not parent.isValid():
|
||||
pitem = self.root
|
||||
else:
|
||||
pitem = parent.internalPointer()
|
||||
|
||||
return len(pitem.children)
|
||||
|
||||
def init_data(self):
|
||||
for (cat, items) in self._data.items():
|
||||
newcat = CompletionItem([cat], self.root)
|
||||
self.root.children.append(newcat)
|
||||
for item in items:
|
||||
newitem = CompletionItem(item, newcat)
|
||||
newcat.children.append(newitem)
|
||||
|
||||
class CompletionItem():
|
||||
parent = None
|
||||
_data = None
|
||||
children = None
|
||||
_marks = None
|
||||
|
||||
def __init__(self, data, parent=None):
|
||||
self.parent = parent
|
||||
self._data = data
|
||||
self.children = []
|
||||
self._marks = []
|
||||
|
||||
def data(self, column, role=Qt.DisplayRole):
|
||||
if role == Qt.DisplayRole:
|
||||
return self._data[column]
|
||||
elif role == Qt.UserRole:
|
||||
return self._marks
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
def setdata(self, column, value, role=Qt.DisplayRole):
|
||||
if role == Qt.DisplayRole:
|
||||
self._data[column] = value
|
||||
elif role == Qt.UserRole:
|
||||
self._marks = value
|
||||
else:
|
||||
raise ValueError
|
||||
|
||||
def column_count(self):
|
||||
return len(self._data)
|
||||
|
||||
def row(self):
|
||||
if self.parent:
|
||||
return self.parent.children.index(self)
|
||||
return 0
|
||||
|
||||
class CompletionFilterModel(QSortFilterProxyModel):
|
||||
_pattern = None
|
||||
# FIXME sort in a way strings starting with pattern are first
|
||||
|
||||
@property
|
||||
def pattern(self):
|
||||
return self._pattern
|
||||
|
||||
@pattern.setter
|
||||
def pattern(self, val):
|
||||
self._pattern = val
|
||||
self.invalidateFilter()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.pattern = ''
|
||||
|
||||
def filterAcceptsRow(self, row, parent):
|
||||
if parent == QModelIndex():
|
||||
return True
|
||||
idx = self.sourceModel().index(row, 0, parent);
|
||||
data = self.sourceModel().data(idx).value()
|
||||
# TODO more sophisticated filtering
|
||||
if not self.pattern:
|
||||
return True
|
||||
return self.pattern in data
|
||||
|
@ -1,66 +1,66 @@
|
||||
import os.path
|
||||
import os
|
||||
import logging
|
||||
|
||||
from configparser import ConfigParser
|
||||
|
||||
default_config = {
|
||||
'keybind': {
|
||||
'o': 'open',
|
||||
'O': 'tabopen',
|
||||
'd': 'tabclose',
|
||||
'J': 'tabnext',
|
||||
'K': 'tabprev',
|
||||
'r': 'reload',
|
||||
'H': 'back',
|
||||
'L': 'forward',
|
||||
'h': 'scroll -50 0',
|
||||
'j': 'scroll 0 50',
|
||||
'k': 'scroll 0 -50',
|
||||
'l': 'scroll 50 0',
|
||||
'u': 'undo',
|
||||
'gg': 'scrollpercenty 0',
|
||||
'G': 'scrollpercenty',
|
||||
}
|
||||
}
|
||||
|
||||
class Config(ConfigParser):
|
||||
"""Our own ConfigParser"""
|
||||
configdir = None
|
||||
FNAME = 'config'
|
||||
|
||||
def __init__(self, configdir):
|
||||
"""configdir: directory to store the config in"""
|
||||
super().__init__()
|
||||
self.optionxform = lambda opt: opt # be case-insensitive
|
||||
self.configdir = configdir
|
||||
if self.configdir is None:
|
||||
self.init_config()
|
||||
return
|
||||
self.configfile = os.path.join(self.configdir, self.FNAME)
|
||||
if not os.path.isfile(self.configfile):
|
||||
self.init_config()
|
||||
logging.debug("Reading config from {}".format(self.configfile))
|
||||
self.read(self.configfile)
|
||||
|
||||
def init_config(self):
|
||||
logging.info("Initializing default config.")
|
||||
if self.configdir is None:
|
||||
self.read_dict(default_config)
|
||||
return
|
||||
cp = ConfigParser()
|
||||
cp.optionxform = lambda opt: opt # be case-insensitive
|
||||
cp.read_dict(default_config)
|
||||
if not os.path.exists(self.configdir):
|
||||
os.makedirs(self.configdir, 0o755)
|
||||
with open(self.configfile, 'w') as f:
|
||||
cp.write(f)
|
||||
|
||||
def save(self):
|
||||
if self.configdir is None:
|
||||
return
|
||||
if not os.path.exists(self.configdir):
|
||||
os.makedirs(self.configdir, 0o755)
|
||||
logging.debug("Saving config to {}".format(self.configfile))
|
||||
with open(self.configfile, 'w') as f:
|
||||
self.write(f)
|
||||
import os.path
|
||||
import os
|
||||
import logging
|
||||
|
||||
from configparser import ConfigParser
|
||||
|
||||
default_config = {
|
||||
'keybind': {
|
||||
'o': 'open',
|
||||
'O': 'tabopen',
|
||||
'd': 'tabclose',
|
||||
'J': 'tabnext',
|
||||
'K': 'tabprev',
|
||||
'r': 'reload',
|
||||
'H': 'back',
|
||||
'L': 'forward',
|
||||
'h': 'scroll -50 0',
|
||||
'j': 'scroll 0 50',
|
||||
'k': 'scroll 0 -50',
|
||||
'l': 'scroll 50 0',
|
||||
'u': 'undo',
|
||||
'gg': 'scrollpercenty 0',
|
||||
'G': 'scrollpercenty',
|
||||
}
|
||||
}
|
||||
|
||||
class Config(ConfigParser):
|
||||
"""Our own ConfigParser"""
|
||||
configdir = None
|
||||
FNAME = 'config'
|
||||
|
||||
def __init__(self, configdir):
|
||||
"""configdir: directory to store the config in"""
|
||||
super().__init__()
|
||||
self.optionxform = lambda opt: opt # be case-insensitive
|
||||
self.configdir = configdir
|
||||
if self.configdir is None:
|
||||
self.init_config()
|
||||
return
|
||||
self.configfile = os.path.join(self.configdir, self.FNAME)
|
||||
if not os.path.isfile(self.configfile):
|
||||
self.init_config()
|
||||
logging.debug("Reading config from {}".format(self.configfile))
|
||||
self.read(self.configfile)
|
||||
|
||||
def init_config(self):
|
||||
logging.info("Initializing default config.")
|
||||
if self.configdir is None:
|
||||
self.read_dict(default_config)
|
||||
return
|
||||
cp = ConfigParser()
|
||||
cp.optionxform = lambda opt: opt # be case-insensitive
|
||||
cp.read_dict(default_config)
|
||||
if not os.path.exists(self.configdir):
|
||||
os.makedirs(self.configdir, 0o755)
|
||||
with open(self.configfile, 'w') as f:
|
||||
cp.write(f)
|
||||
|
||||
def save(self):
|
||||
if self.configdir is None:
|
||||
return
|
||||
if not os.path.exists(self.configdir):
|
||||
os.makedirs(self.configdir, 0o755)
|
||||
logging.debug("Saving config to {}".format(self.configfile))
|
||||
with open(self.configfile, 'w') as f:
|
||||
self.write(f)
|
||||
|
@ -1,129 +1,129 @@
|
||||
import logging
|
||||
|
||||
from PyQt5.QtWidgets import QLineEdit, QShortcut
|
||||
from PyQt5.QtCore import pyqtSignal, Qt
|
||||
from PyQt5.QtGui import QValidator, QKeySequence
|
||||
|
||||
from qutebrowser.commands.utils import CommandCompletionModel
|
||||
|
||||
class Command(QLineEdit):
|
||||
"""The commandline part of the statusbar"""
|
||||
|
||||
got_cmd = pyqtSignal(str) # Emitted when a command is triggered by the user
|
||||
bar = None # The status bar object
|
||||
esc_pressed = pyqtSignal() # Emitted when escape is pressed
|
||||
tab_pressed = pyqtSignal(bool) # Emitted when tab is pressed (arg: shift)
|
||||
hide_completion = pyqtSignal() # Hide completion window
|
||||
history = [] # The command history, with newer commands at the bottom
|
||||
_tmphist = []
|
||||
_histpos = None
|
||||
|
||||
# FIXME won't the tab key switch to the next widget?
|
||||
# See http://www.saltycrane.com/blog/2008/01/how-to-capture-tab-key-press-event-with/
|
||||
# for a possible fix.
|
||||
|
||||
def __init__(self, bar):
|
||||
super().__init__(bar)
|
||||
# FIXME
|
||||
self.bar = bar
|
||||
self.setStyleSheet("border: 0px; padding-left: 1px")
|
||||
self.setValidator(Validator())
|
||||
self.returnPressed.connect(self.process_cmd)
|
||||
self.textEdited.connect(self._histbrowse_stop)
|
||||
|
||||
for (key, handler) in [(Qt.Key_Escape, self.esc_pressed),
|
||||
(Qt.Key_Up, self.key_up_handler),
|
||||
(Qt.Key_Down, self.key_down_handler),
|
||||
(Qt.Key_Tab | Qt.SHIFT, self.key_stab_handler),
|
||||
(Qt.Key_Tab, self.key_tab_handler)]:
|
||||
sc = QShortcut(self)
|
||||
sc.setKey(QKeySequence(key))
|
||||
sc.setContext(Qt.WidgetWithChildrenShortcut)
|
||||
sc.activated.connect(handler)
|
||||
|
||||
def process_cmd(self):
|
||||
"""Handle the command in the status bar"""
|
||||
self._histbrowse_stop()
|
||||
text = self.text().lstrip(':')
|
||||
if not self.history or text != self.history[-1]:
|
||||
self.history.append(text)
|
||||
self.setText('')
|
||||
self.got_cmd.emit(text)
|
||||
|
||||
def set_cmd(self, text):
|
||||
"""Preset the statusbar to some text"""
|
||||
self.setText(':' + text)
|
||||
self.setFocus()
|
||||
|
||||
def append_cmd(self, text):
|
||||
"""Append text to the commandline"""
|
||||
# FIXME do the right thing here
|
||||
self.setText(':' + text)
|
||||
self.setFocus()
|
||||
|
||||
def focusOutEvent(self, e):
|
||||
"""Clear the statusbar text if it's explicitely unfocused"""
|
||||
if e.reason() in [Qt.MouseFocusReason, Qt.TabFocusReason,
|
||||
Qt.BacktabFocusReason, Qt.OtherFocusReason]:
|
||||
self.setText('')
|
||||
self._histbrowse_stop()
|
||||
self.hide_completion.emit()
|
||||
super().focusOutEvent(e)
|
||||
|
||||
def focusInEvent(self, e):
|
||||
"""Clear error message when the statusbar is focused"""
|
||||
self.bar.clear_error()
|
||||
super().focusInEvent(e)
|
||||
|
||||
def _histbrowse_start(self):
|
||||
pre = self.text().strip().lstrip(':')
|
||||
logging.debug('Preset text: "{}"'.format(pre))
|
||||
if pre:
|
||||
self._tmphist = [e for e in self.history if e.startswith(pre)]
|
||||
else:
|
||||
self._tmphist = self.history
|
||||
self._histpos = len(self._tmphist) - 1
|
||||
|
||||
def _histbrowse_stop(self):
|
||||
self._histpos = None
|
||||
|
||||
def key_up_handler(self):
|
||||
logging.debug("history up [pre]: pos {}".format(self._histpos))
|
||||
if self._histpos is None:
|
||||
self._histbrowse_start()
|
||||
elif self._histpos <= 0:
|
||||
return
|
||||
else:
|
||||
self._histpos -= 1
|
||||
if not self._tmphist:
|
||||
return
|
||||
logging.debug("history up: {} / len {} / pos {}".format(
|
||||
self._tmphist, len(self._tmphist), self._histpos))
|
||||
self.set_cmd(self._tmphist[self._histpos])
|
||||
|
||||
def key_down_handler(self):
|
||||
logging.debug("history up [pre]: pos {}".format(self._histpos,
|
||||
self._tmphist, len(self._tmphist), self._histpos))
|
||||
if (self._histpos is None or
|
||||
self._histpos >= len(self._tmphist) - 1 or
|
||||
not self._tmphist):
|
||||
return
|
||||
self._histpos += 1
|
||||
logging.debug("history up: {} / len {} / pos {}".format(
|
||||
self._tmphist, len(self._tmphist), self._histpos))
|
||||
self.set_cmd(self._tmphist[self._histpos])
|
||||
|
||||
def key_tab_handler(self):
|
||||
self.tab_pressed.emit(False)
|
||||
|
||||
def key_stab_handler(self):
|
||||
self.tab_pressed.emit(True)
|
||||
|
||||
class Validator(QValidator):
|
||||
"""Validator to prevent the : from getting deleted"""
|
||||
def validate(self, string, pos):
|
||||
if string.startswith(':'):
|
||||
return (QValidator.Acceptable, string, pos)
|
||||
else:
|
||||
return (QValidator.Invalid, string, pos)
|
||||
|
||||
import logging
|
||||
|
||||
from PyQt5.QtWidgets import QLineEdit, QShortcut
|
||||
from PyQt5.QtCore import pyqtSignal, Qt
|
||||
from PyQt5.QtGui import QValidator, QKeySequence
|
||||
|
||||
from qutebrowser.commands.utils import CommandCompletionModel
|
||||
|
||||
class Command(QLineEdit):
|
||||
"""The commandline part of the statusbar"""
|
||||
|
||||
got_cmd = pyqtSignal(str) # Emitted when a command is triggered by the user
|
||||
bar = None # The status bar object
|
||||
esc_pressed = pyqtSignal() # Emitted when escape is pressed
|
||||
tab_pressed = pyqtSignal(bool) # Emitted when tab is pressed (arg: shift)
|
||||
hide_completion = pyqtSignal() # Hide completion window
|
||||
history = [] # The command history, with newer commands at the bottom
|
||||
_tmphist = []
|
||||
_histpos = None
|
||||
|
||||
# FIXME won't the tab key switch to the next widget?
|
||||
# See http://www.saltycrane.com/blog/2008/01/how-to-capture-tab-key-press-event-with/
|
||||
# for a possible fix.
|
||||
|
||||
def __init__(self, bar):
|
||||
super().__init__(bar)
|
||||
# FIXME
|
||||
self.bar = bar
|
||||
self.setStyleSheet("border: 0px; padding-left: 1px")
|
||||
self.setValidator(Validator())
|
||||
self.returnPressed.connect(self.process_cmd)
|
||||
self.textEdited.connect(self._histbrowse_stop)
|
||||
|
||||
for (key, handler) in [(Qt.Key_Escape, self.esc_pressed),
|
||||
(Qt.Key_Up, self.key_up_handler),
|
||||
(Qt.Key_Down, self.key_down_handler),
|
||||
(Qt.Key_Tab | Qt.SHIFT, self.key_stab_handler),
|
||||
(Qt.Key_Tab, self.key_tab_handler)]:
|
||||
sc = QShortcut(self)
|
||||
sc.setKey(QKeySequence(key))
|
||||
sc.setContext(Qt.WidgetWithChildrenShortcut)
|
||||
sc.activated.connect(handler)
|
||||
|
||||
def process_cmd(self):
|
||||
"""Handle the command in the status bar"""
|
||||
self._histbrowse_stop()
|
||||
text = self.text().lstrip(':')
|
||||
if not self.history or text != self.history[-1]:
|
||||
self.history.append(text)
|
||||
self.setText('')
|
||||
self.got_cmd.emit(text)
|
||||
|
||||
def set_cmd(self, text):
|
||||
"""Preset the statusbar to some text"""
|
||||
self.setText(':' + text)
|
||||
self.setFocus()
|
||||
|
||||
def append_cmd(self, text):
|
||||
"""Append text to the commandline"""
|
||||
# FIXME do the right thing here
|
||||
self.setText(':' + text)
|
||||
self.setFocus()
|
||||
|
||||
def focusOutEvent(self, e):
|
||||
"""Clear the statusbar text if it's explicitely unfocused"""
|
||||
if e.reason() in [Qt.MouseFocusReason, Qt.TabFocusReason,
|
||||
Qt.BacktabFocusReason, Qt.OtherFocusReason]:
|
||||
self.setText('')
|
||||
self._histbrowse_stop()
|
||||
self.hide_completion.emit()
|
||||
super().focusOutEvent(e)
|
||||
|
||||
def focusInEvent(self, e):
|
||||
"""Clear error message when the statusbar is focused"""
|
||||
self.bar.clear_error()
|
||||
super().focusInEvent(e)
|
||||
|
||||
def _histbrowse_start(self):
|
||||
pre = self.text().strip().lstrip(':')
|
||||
logging.debug('Preset text: "{}"'.format(pre))
|
||||
if pre:
|
||||
self._tmphist = [e for e in self.history if e.startswith(pre)]
|
||||
else:
|
||||
self._tmphist = self.history
|
||||
self._histpos = len(self._tmphist) - 1
|
||||
|
||||
def _histbrowse_stop(self):
|
||||
self._histpos = None
|
||||
|
||||
def key_up_handler(self):
|
||||
logging.debug("history up [pre]: pos {}".format(self._histpos))
|
||||
if self._histpos is None:
|
||||
self._histbrowse_start()
|
||||
elif self._histpos <= 0:
|
||||
return
|
||||
else:
|
||||
self._histpos -= 1
|
||||
if not self._tmphist:
|
||||
return
|
||||
logging.debug("history up: {} / len {} / pos {}".format(
|
||||
self._tmphist, len(self._tmphist), self._histpos))
|
||||
self.set_cmd(self._tmphist[self._histpos])
|
||||
|
||||
def key_down_handler(self):
|
||||
logging.debug("history up [pre]: pos {}".format(self._histpos,
|
||||
self._tmphist, len(self._tmphist), self._histpos))
|
||||
if (self._histpos is None or
|
||||
self._histpos >= len(self._tmphist) - 1 or
|
||||
not self._tmphist):
|
||||
return
|
||||
self._histpos += 1
|
||||
logging.debug("history up: {} / len {} / pos {}".format(
|
||||
self._tmphist, len(self._tmphist), self._histpos))
|
||||
self.set_cmd(self._tmphist[self._histpos])
|
||||
|
||||
def key_tab_handler(self):
|
||||
self.tab_pressed.emit(False)
|
||||
|
||||
def key_stab_handler(self):
|
||||
self.tab_pressed.emit(True)
|
||||
|
||||
class Validator(QValidator):
|
||||
"""Validator to prevent the : from getting deleted"""
|
||||
def validate(self, string, pos):
|
||||
if string.startswith(':'):
|
||||
return (QValidator.Acceptable, string, pos)
|
||||
else:
|
||||
return (QValidator.Invalid, string, pos)
|
||||
|
||||
|
@ -1,47 +1,47 @@
|
||||
from PyQt5.QtWidgets import QProgressBar, QSizePolicy
|
||||
from PyQt5.QtCore import QSize
|
||||
|
||||
class Progress(QProgressBar):
|
||||
""" The progress bar part of the status bar"""
|
||||
bar = None
|
||||
_stylesheet = """
|
||||
QProgressBar {
|
||||
border-radius: 0px;
|
||||
border: 2px solid transparent;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
QProgressBar::chunk {
|
||||
background-color: white;
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, bar):
|
||||
self.bar = bar
|
||||
super().__init__(bar)
|
||||
|
||||
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
||||
self.setTextVisible(False)
|
||||
self.setStyleSheet(self._stylesheet.strip())
|
||||
self.hide()
|
||||
|
||||
def minimumSizeHint(self):
|
||||
status_size = self.bar.size()
|
||||
return QSize(100, status_size.height())
|
||||
|
||||
def sizeHint(self):
|
||||
return self.minimumSizeHint()
|
||||
|
||||
def set_progress(self, prog):
|
||||
"""Sets the progress of the bar and shows/hides it if necessary"""
|
||||
# TODO display failed loading in some meaningful way?
|
||||
if prog == 100:
|
||||
self.setValue(prog)
|
||||
self.hide()
|
||||
else:
|
||||
self.setValue(prog)
|
||||
self.show()
|
||||
|
||||
def load_finished(self, ok):
|
||||
self.hide()
|
||||
|
||||
from PyQt5.QtWidgets import QProgressBar, QSizePolicy
|
||||
from PyQt5.QtCore import QSize
|
||||
|
||||
class Progress(QProgressBar):
|
||||
""" The progress bar part of the status bar"""
|
||||
bar = None
|
||||
_stylesheet = """
|
||||
QProgressBar {
|
||||
border-radius: 0px;
|
||||
border: 2px solid transparent;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
QProgressBar::chunk {
|
||||
background-color: white;
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, bar):
|
||||
self.bar = bar
|
||||
super().__init__(bar)
|
||||
|
||||
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
||||
self.setTextVisible(False)
|
||||
self.setStyleSheet(self._stylesheet.strip())
|
||||
self.hide()
|
||||
|
||||
def minimumSizeHint(self):
|
||||
status_size = self.bar.size()
|
||||
return QSize(100, status_size.height())
|
||||
|
||||
def sizeHint(self):
|
||||
return self.minimumSizeHint()
|
||||
|
||||
def set_progress(self, prog):
|
||||
"""Sets the progress of the bar and shows/hides it if necessary"""
|
||||
# TODO display failed loading in some meaningful way?
|
||||
if prog == 100:
|
||||
self.setValue(prog)
|
||||
self.hide()
|
||||
else:
|
||||
self.setValue(prog)
|
||||
self.show()
|
||||
|
||||
def load_finished(self, ok):
|
||||
self.hide()
|
||||
|
||||
|
@ -1,35 +1,35 @@
|
||||
from PyQt5.QtWidgets import QLabel
|
||||
|
||||
class Text(QLabel):
|
||||
"""The text part of the status bar, composed of several 'widgets'"""
|
||||
keystring = ''
|
||||
error = ''
|
||||
text = ''
|
||||
scrollperc = ''
|
||||
|
||||
def __init__(self, bar):
|
||||
super().__init__(bar)
|
||||
self.setStyleSheet("padding-right: 1px")
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
super().__setattr__(name, value)
|
||||
self.update()
|
||||
|
||||
def set_keystring(self, s):
|
||||
"""Setter to be used as a Qt slot"""
|
||||
self.keystring = s
|
||||
|
||||
def set_perc(self, x, y):
|
||||
"""Setter to be used as a Qt slot"""
|
||||
if y == 0:
|
||||
self.scrollperc = '[top]'
|
||||
elif y == 100:
|
||||
self.scrollperc = '[bot]'
|
||||
else:
|
||||
self.scrollperc = '[{}%]'.format(y)
|
||||
|
||||
def update(self):
|
||||
"""Update the text displayed"""
|
||||
self.setText(' '.join([self.keystring, self.error, self.text,
|
||||
self.scrollperc]))
|
||||
|
||||
from PyQt5.QtWidgets import QLabel
|
||||
|
||||
class Text(QLabel):
|
||||
"""The text part of the status bar, composed of several 'widgets'"""
|
||||
keystring = ''
|
||||
error = ''
|
||||
text = ''
|
||||
scrollperc = ''
|
||||
|
||||
def __init__(self, bar):
|
||||
super().__init__(bar)
|
||||
self.setStyleSheet("padding-right: 1px")
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
super().__setattr__(name, value)
|
||||
self.update()
|
||||
|
||||
def set_keystring(self, s):
|
||||
"""Setter to be used as a Qt slot"""
|
||||
self.keystring = s
|
||||
|
||||
def set_perc(self, x, y):
|
||||
"""Setter to be used as a Qt slot"""
|
||||
if y == 0:
|
||||
self.scrollperc = '[top]'
|
||||
elif y == 100:
|
||||
self.scrollperc = '[bot]'
|
||||
else:
|
||||
self.scrollperc = '[{}%]'.format(y)
|
||||
|
||||
def update(self):
|
||||
"""Update the text displayed"""
|
||||
self.setText(' '.join([self.keystring, self.error, self.text,
|
||||
self.scrollperc]))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user