forked from openlp/openlp
Add Ability to hide plugins
bzr-revno: 587
This commit is contained in:
commit
9a8c045f2b
@ -118,7 +118,7 @@ class MediaManagerItem(QtGui.QWidget):
|
|||||||
self.requiredIcons()
|
self.requiredIcons()
|
||||||
self.setupUi()
|
self.setupUi()
|
||||||
self.retranslateUi()
|
self.retranslateUi()
|
||||||
self.initialise()
|
#self.initialise()
|
||||||
|
|
||||||
def requiredIcons(self):
|
def requiredIcons(self):
|
||||||
"""
|
"""
|
||||||
@ -131,7 +131,6 @@ class MediaManagerItem(QtGui.QWidget):
|
|||||||
self.hasFileIcon = False
|
self.hasFileIcon = False
|
||||||
self.hasDeleteIcon = True
|
self.hasDeleteIcon = True
|
||||||
|
|
||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
"""
|
"""
|
||||||
This method is called automatically to provide OpenLP with the
|
This method is called automatically to provide OpenLP with the
|
||||||
|
@ -31,8 +31,9 @@ class PluginStatus(object):
|
|||||||
"""
|
"""
|
||||||
Defines the status of the plugin
|
Defines the status of the plugin
|
||||||
"""
|
"""
|
||||||
Active = 1
|
Active = 0
|
||||||
Inactive = 2
|
Inactive = 1
|
||||||
|
Disabled = 2
|
||||||
|
|
||||||
class Plugin(object):
|
class Plugin(object):
|
||||||
"""
|
"""
|
||||||
@ -85,17 +86,6 @@ class Plugin(object):
|
|||||||
``about()``
|
``about()``
|
||||||
Used in the plugin manager, when a person clicks on the 'About' button.
|
Used in the plugin manager, when a person clicks on the 'About' button.
|
||||||
|
|
||||||
``save(data)``
|
|
||||||
A method to convert the plugin's data to a string to be stored in the
|
|
||||||
Service file.
|
|
||||||
|
|
||||||
``load(string)``
|
|
||||||
A method to convert the string from a Service file into the plugin's
|
|
||||||
own data format.
|
|
||||||
|
|
||||||
``render(theme, screen_number)``
|
|
||||||
A method used to render something to the screen, given the current theme
|
|
||||||
and screen number.
|
|
||||||
"""
|
"""
|
||||||
global log
|
global log
|
||||||
log = logging.getLogger(u'Plugin')
|
log = logging.getLogger(u'Plugin')
|
||||||
@ -129,6 +119,9 @@ class Plugin(object):
|
|||||||
self.icon = None
|
self.icon = None
|
||||||
self.config = PluginConfig(self.name)
|
self.config = PluginConfig(self.name)
|
||||||
self.weight = 0
|
self.weight = 0
|
||||||
|
self.media_id = -1
|
||||||
|
self.settings_id = -1
|
||||||
|
self.media_active = False
|
||||||
self.status = PluginStatus.Inactive
|
self.status = PluginStatus.Inactive
|
||||||
# Set up logging
|
# Set up logging
|
||||||
self.log = logging.getLogger(self.name)
|
self.log = logging.getLogger(self.name)
|
||||||
@ -137,6 +130,7 @@ class Plugin(object):
|
|||||||
self.render_manager = plugin_helpers[u'render']
|
self.render_manager = plugin_helpers[u'render']
|
||||||
self.service_manager = plugin_helpers[u'service']
|
self.service_manager = plugin_helpers[u'service']
|
||||||
self.settings = plugin_helpers[u'settings']
|
self.settings = plugin_helpers[u'settings']
|
||||||
|
self.mediatoolbox = plugin_helpers[u'toolbox']
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'%s_add_service_item'% self.name), self.process_add_service_event)
|
QtCore.SIGNAL(u'%s_add_service_item'% self.name), self.process_add_service_event)
|
||||||
|
|
||||||
@ -157,6 +151,28 @@ class Plugin(object):
|
|||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def set_status(self):
|
||||||
|
"""
|
||||||
|
Sets the status of the plugin
|
||||||
|
"""
|
||||||
|
self.status = self.config.get_config(\
|
||||||
|
u'%s_status' % self.name, PluginStatus.Inactive)
|
||||||
|
|
||||||
|
def toggle_status(self, new_status):
|
||||||
|
"""
|
||||||
|
Changes the status of the plugin and remembers it
|
||||||
|
"""
|
||||||
|
self.status = new_status
|
||||||
|
self.config.set_config(u'%s_status' % self.name, self.status)
|
||||||
|
|
||||||
|
def is_active(self):
|
||||||
|
"""
|
||||||
|
Indicates if the plugin is active
|
||||||
|
|
||||||
|
Returns True or False.
|
||||||
|
"""
|
||||||
|
return int(self.status ) == int(PluginStatus.Active)
|
||||||
|
|
||||||
def get_media_manager_item(self):
|
def get_media_manager_item(self):
|
||||||
"""
|
"""
|
||||||
Construct a MediaManagerItem object with all the buttons and things
|
Construct a MediaManagerItem object with all the buttons and things
|
||||||
@ -224,7 +240,8 @@ class Plugin(object):
|
|||||||
"""
|
"""
|
||||||
Called by the plugin Manager to initialise anything it needs.
|
Called by the plugin Manager to initialise anything it needs.
|
||||||
"""
|
"""
|
||||||
pass
|
if self.media_item is not None:
|
||||||
|
self.media_item.initialise()
|
||||||
|
|
||||||
def finalise(self):
|
def finalise(self):
|
||||||
"""
|
"""
|
||||||
@ -232,3 +249,25 @@ class Plugin(object):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def remove_toolbox_item(self):
|
||||||
|
"""
|
||||||
|
Called by the plugin to remove toolbar
|
||||||
|
"""
|
||||||
|
if self.media_id is not -1:
|
||||||
|
self.mediatoolbox.removeItem(self.media_id)
|
||||||
|
if self.settings_id is not -1:
|
||||||
|
self.settings.removeTab(self.settings_id)
|
||||||
|
self.media_active = False
|
||||||
|
|
||||||
|
def insert_toolbox_item(self):
|
||||||
|
"""
|
||||||
|
Called by plugin to replace toolbar
|
||||||
|
"""
|
||||||
|
if not self.media_active:
|
||||||
|
if self.media_id is not -1:
|
||||||
|
self.mediatoolbox.insertItem(
|
||||||
|
self.media_id, self.media_item, self.icon, self.media_item.title)
|
||||||
|
if self.settings_id is not -1:
|
||||||
|
self.settings.insertTab(
|
||||||
|
self.settings_id, self.settings_tab)
|
||||||
|
self.media_active = True
|
||||||
|
@ -105,7 +105,12 @@ class PluginManager(object):
|
|||||||
for plugin in plugins_list:
|
for plugin in plugins_list:
|
||||||
if plugin.check_pre_conditions():
|
if plugin.check_pre_conditions():
|
||||||
log.debug(u'Plugin %s active', unicode(plugin.name))
|
log.debug(u'Plugin %s active', unicode(plugin.name))
|
||||||
plugin.status = PluginStatus.Active
|
if plugin.can_be_disabled():
|
||||||
|
plugin.set_status()
|
||||||
|
else:
|
||||||
|
plugin.status = PluginStatus.Active
|
||||||
|
else:
|
||||||
|
plugin.status = PluginStatus.Disabled
|
||||||
self.plugins.append(plugin)
|
self.plugins.append(plugin)
|
||||||
|
|
||||||
def order_by_weight(self, x, y):
|
def order_by_weight(self, x, y):
|
||||||
@ -129,13 +134,14 @@ class PluginManager(object):
|
|||||||
The Media Manager itself.
|
The Media Manager itself.
|
||||||
"""
|
"""
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
if plugin.status == PluginStatus.Active:
|
if plugin.status is not PluginStatus.Disabled:
|
||||||
media_manager_item = plugin.get_media_manager_item()
|
plugin.media_item = plugin.get_media_manager_item()
|
||||||
if media_manager_item is not None:
|
if plugin.media_item is not None:
|
||||||
log.debug(u'Inserting media manager item from %s' % \
|
log.debug(u'Inserting media manager item from %s' % \
|
||||||
plugin.name)
|
plugin.name)
|
||||||
mediatoolbox.addItem(media_manager_item, plugin.icon,
|
plugin.media_id = mediatoolbox.addItem(
|
||||||
media_manager_item.title)
|
plugin.media_item, plugin.icon, plugin.media_item.title)
|
||||||
|
plugin.media_active = True
|
||||||
|
|
||||||
def hook_settings_tabs(self, settingsform=None):
|
def hook_settings_tabs(self, settingsform=None):
|
||||||
"""
|
"""
|
||||||
@ -147,12 +153,13 @@ class PluginManager(object):
|
|||||||
Defaults to *None*. The settings form to add tabs to.
|
Defaults to *None*. The settings form to add tabs to.
|
||||||
"""
|
"""
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
settings_tab = plugin.get_settings_tab()
|
if plugin.status is not PluginStatus.Disabled:
|
||||||
if settings_tab is not None:
|
plugin.settings_tab = plugin.get_settings_tab()
|
||||||
log.debug(u'Inserting settings tab item from %s' % plugin.name)
|
if plugin.settings_tab is not None:
|
||||||
settingsform.addTab(settings_tab)
|
log.debug(u'Inserting settings tab item from %s' % plugin.name)
|
||||||
else:
|
plugin.settings_id = settingsform.addTab(plugin.settings_tab)
|
||||||
log.debug(u'No settings in %s' % plugin.name)
|
else:
|
||||||
|
log.debug(u'No tab settings in %s' % plugin.name)
|
||||||
|
|
||||||
def hook_import_menu(self, import_menu):
|
def hook_import_menu(self, import_menu):
|
||||||
"""
|
"""
|
||||||
@ -163,7 +170,7 @@ class PluginManager(object):
|
|||||||
The Import menu.
|
The Import menu.
|
||||||
"""
|
"""
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
if plugin.status == PluginStatus.Active:
|
if plugin.status is not PluginStatus.Disabled:
|
||||||
plugin.add_import_menu_item(import_menu)
|
plugin.add_import_menu_item(import_menu)
|
||||||
|
|
||||||
def hook_export_menu(self, export_menu):
|
def hook_export_menu(self, export_menu):
|
||||||
@ -175,7 +182,7 @@ class PluginManager(object):
|
|||||||
The Export menu.
|
The Export menu.
|
||||||
"""
|
"""
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
if plugin.status == PluginStatus.Active:
|
if plugin.status is not PluginStatus.Disabled:
|
||||||
plugin.add_export_menu_item(export_menu)
|
plugin.add_export_menu_item(export_menu)
|
||||||
|
|
||||||
def hook_tools_menu(self, tools_menu):
|
def hook_tools_menu(self, tools_menu):
|
||||||
@ -187,7 +194,7 @@ class PluginManager(object):
|
|||||||
The Tools menu.
|
The Tools menu.
|
||||||
"""
|
"""
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
if plugin.status == PluginStatus.Active:
|
if plugin.status is not PluginStatus.Disabled:
|
||||||
plugin.add_tools_menu_item(tools_menu)
|
plugin.add_tools_menu_item(tools_menu)
|
||||||
|
|
||||||
def initialise_plugins(self):
|
def initialise_plugins(self):
|
||||||
@ -195,15 +202,19 @@ class PluginManager(object):
|
|||||||
Loop through all the plugins and give them an opportunity to
|
Loop through all the plugins and give them an opportunity to
|
||||||
initialise themselves.
|
initialise themselves.
|
||||||
"""
|
"""
|
||||||
|
log.info(u'initialising plugins')
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
if plugin.status == PluginStatus.Active:
|
if plugin.is_active():
|
||||||
plugin.initialise()
|
plugin.initialise()
|
||||||
|
if plugin.media_item is not None and not plugin.is_active():
|
||||||
|
plugin.remove_toolbox_item()
|
||||||
|
|
||||||
def finalise_plugins(self):
|
def finalise_plugins(self):
|
||||||
"""
|
"""
|
||||||
Loop through all the plugins and give them an opportunity to
|
Loop through all the plugins and give them an opportunity to
|
||||||
clean themselves up
|
clean themselves up
|
||||||
"""
|
"""
|
||||||
|
log.info(u'finalising plugins')
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
if plugin.status == PluginStatus.Active:
|
if plugin.is_active():
|
||||||
plugin.finalise()
|
plugin.finalise()
|
||||||
|
@ -109,19 +109,12 @@ class Ui_MainWindow(object):
|
|||||||
self.MediaManagerDock.setObjectName(u'MediaManagerDock')
|
self.MediaManagerDock.setObjectName(u'MediaManagerDock')
|
||||||
self.MediaManagerDock.setMinimumWidth(
|
self.MediaManagerDock.setMinimumWidth(
|
||||||
self.settingsmanager.mainwindow_left)
|
self.settingsmanager.mainwindow_left)
|
||||||
|
|
||||||
# self.MediaManagerDock.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Ignored,
|
|
||||||
# QtGui.QSizePolicy.Maximum))
|
|
||||||
# geometry = self.MediaManagerDock.geometry()
|
|
||||||
# geometry.setWidth(self.settingsmanager.mainwindow_left)
|
|
||||||
# self.MediaManagerDock.setGeometry(geometry)
|
|
||||||
# self.MediaManagerDock.setMinimumWidth(10)
|
|
||||||
|
|
||||||
self.MediaManagerContents = QtGui.QWidget()
|
self.MediaManagerContents = QtGui.QWidget()
|
||||||
self.MediaManagerContents.setObjectName(u'MediaManagerContents')
|
self.MediaManagerContents.setObjectName(u'MediaManagerContents')
|
||||||
self.MediaManagerLayout = QtGui.QHBoxLayout(self.MediaManagerContents)
|
self.MediaManagerLayout = QtGui.QHBoxLayout(self.MediaManagerContents)
|
||||||
self.MediaManagerLayout.setContentsMargins(0, 2, 0, 0)
|
self.MediaManagerLayout.setContentsMargins(0, 2, 0, 0)
|
||||||
self.MediaManagerLayout.setObjectName(u'MediaManagerLayout')
|
self.MediaManagerLayout.setObjectName(u'MediaManagerLayout')
|
||||||
|
# Create the media toolbox
|
||||||
self.MediaToolBox = QtGui.QToolBox(self.MediaManagerContents)
|
self.MediaToolBox = QtGui.QToolBox(self.MediaManagerContents)
|
||||||
self.MediaToolBox.setObjectName(u'MediaToolBox')
|
self.MediaToolBox.setObjectName(u'MediaToolBox')
|
||||||
self.MediaManagerLayout.addWidget(self.MediaToolBox)
|
self.MediaManagerLayout.addWidget(self.MediaToolBox)
|
||||||
@ -503,6 +496,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
self.plugin_helpers[u'render'] = self.RenderManager
|
self.plugin_helpers[u'render'] = self.RenderManager
|
||||||
self.plugin_helpers[u'service'] = self.ServiceManagerContents
|
self.plugin_helpers[u'service'] = self.ServiceManagerContents
|
||||||
self.plugin_helpers[u'settings'] = self.settingsForm
|
self.plugin_helpers[u'settings'] = self.settingsForm
|
||||||
|
self.plugin_helpers[u'toolbox'] = self.MediaToolBox
|
||||||
self.plugin_manager.find_plugins(pluginpath, self.plugin_helpers)
|
self.plugin_manager.find_plugins(pluginpath, self.plugin_helpers)
|
||||||
# hook methods have to happen after find_plugins. Find plugins needs
|
# hook methods have to happen after find_plugins. Find plugins needs
|
||||||
# the controllers hence the hooks have moved from setupUI() to here
|
# the controllers hence the hooks have moved from setupUI() to here
|
||||||
@ -528,6 +522,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
log.info(u'Load data from Settings')
|
log.info(u'Load data from Settings')
|
||||||
self.settingsForm.postSetUp()
|
self.settingsForm.postSetUp()
|
||||||
|
|
||||||
|
|
||||||
def getMonitorNumber(self):
|
def getMonitorNumber(self):
|
||||||
"""
|
"""
|
||||||
Set up the default behaviour of the monitor configuration in
|
Set up the default behaviour of the monitor configuration in
|
||||||
|
@ -11,6 +11,20 @@ import logging
|
|||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
from openlp.core.lib import translate, PluginStatus, buildIcon
|
from openlp.core.lib import translate, PluginStatus, buildIcon
|
||||||
|
|
||||||
|
class PluginCombo(QtGui.QComboBox):
|
||||||
|
"""
|
||||||
|
Customised version of QTableWidget which can respond to keyboard
|
||||||
|
events.
|
||||||
|
"""
|
||||||
|
def __init__(self, parent=None, plugin=None):
|
||||||
|
QtGui.QComboBox.__init__(self, parent)
|
||||||
|
self.parent = parent
|
||||||
|
self.plugin = plugin
|
||||||
|
|
||||||
|
def enterEvent(self, event):
|
||||||
|
self.parent.activePlugin = self.plugin
|
||||||
|
event.ignore()
|
||||||
|
|
||||||
class PluginForm(QtGui.QDialog):
|
class PluginForm(QtGui.QDialog):
|
||||||
global log
|
global log
|
||||||
log = logging.getLogger(u'PluginForm')
|
log = logging.getLogger(u'PluginForm')
|
||||||
@ -18,6 +32,7 @@ class PluginForm(QtGui.QDialog):
|
|||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QtGui.QDialog.__init__(self, parent)
|
QtGui.QDialog.__init__(self, parent)
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
self.activePlugin = None
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
log.debug(u'Defined')
|
log.debug(u'Defined')
|
||||||
|
|
||||||
@ -57,7 +72,6 @@ class PluginForm(QtGui.QDialog):
|
|||||||
self.AboutTextLabel.setWordWrap(True)
|
self.AboutTextLabel.setWordWrap(True)
|
||||||
self.AboutTextLabel.setObjectName("AboutTextLabel")
|
self.AboutTextLabel.setObjectName("AboutTextLabel")
|
||||||
|
|
||||||
|
|
||||||
self.retranslateUi(PluginForm)
|
self.retranslateUi(PluginForm)
|
||||||
QtCore.QObject.connect(self.ButtonBox,
|
QtCore.QObject.connect(self.ButtonBox,
|
||||||
QtCore.SIGNAL(u'accepted()'), PluginForm.close)
|
QtCore.SIGNAL(u'accepted()'), PluginForm.close)
|
||||||
@ -92,19 +106,20 @@ class PluginForm(QtGui.QDialog):
|
|||||||
self.PluginViewList.setItem(row, 0, item1)
|
self.PluginViewList.setItem(row, 0, item1)
|
||||||
self.PluginViewList.setItem(row, 1, item2)
|
self.PluginViewList.setItem(row, 1, item2)
|
||||||
if plugin.can_be_disabled():
|
if plugin.can_be_disabled():
|
||||||
combo = QtGui.QComboBox()
|
combo = PluginCombo(self, plugin)
|
||||||
self.PluginViewList.setCellWidget(row, 2, combo)
|
self.PluginViewList.setCellWidget(row, 2, combo)
|
||||||
combo.addItem(translate(u'PluginForm', u'Active'))
|
combo.addItem(translate(u'PluginForm', u'Active'))
|
||||||
combo.addItem(translate(u'PluginForm', u'Inactive'))
|
combo.addItem(translate(u'PluginForm', u'Inactive'))
|
||||||
# if plugin.status == PluginStatus.Active:
|
combo.setCurrentIndex(int(plugin.status))
|
||||||
self.PluginViewList.setRowHeight(row, 25)
|
QtCore.QObject.connect(combo,
|
||||||
|
QtCore.SIGNAL(u'currentIndexChanged(int)'), self.statusComboChanged)
|
||||||
else:
|
else:
|
||||||
item3 = QtGui.QTableWidgetItem(
|
item3 = QtGui.QTableWidgetItem(
|
||||||
translate(u'PluginForm', u'Active'))
|
translate(u'PluginForm', u'Active'))
|
||||||
item3.setTextAlignment(QtCore.Qt.AlignVCenter)
|
item3.setTextAlignment(QtCore.Qt.AlignVCenter)
|
||||||
item3.setFlags(QtCore.Qt.ItemIsSelectable)
|
item3.setFlags(QtCore.Qt.ItemIsSelectable)
|
||||||
self.PluginViewList.setItem(row, 2, item3)
|
self.PluginViewList.setItem(row, 2, item3)
|
||||||
self.PluginViewList.setRowHeight(row, 15)
|
self.PluginViewList.setRowHeight(row, 25)
|
||||||
|
|
||||||
def displayAbout(self, item):
|
def displayAbout(self, item):
|
||||||
if item is None:
|
if item is None:
|
||||||
@ -114,3 +129,10 @@ class PluginForm(QtGui.QDialog):
|
|||||||
if text is not None:
|
if text is not None:
|
||||||
self.AboutTextLabel.setText(translate(u'PluginList', text))
|
self.AboutTextLabel.setText(translate(u'PluginList', text))
|
||||||
|
|
||||||
|
def statusComboChanged(self, status):
|
||||||
|
log.debug(u'Combo status changed %s for plugin %s' %(status, self.activePlugin.name))
|
||||||
|
self.activePlugin.toggle_status(status)
|
||||||
|
if status == PluginStatus.Active:
|
||||||
|
self.activePlugin.initialise()
|
||||||
|
else:
|
||||||
|
self.activePlugin.finalise()
|
||||||
|
@ -47,8 +47,17 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
|
|||||||
self.addTab(self.AlertsTab)
|
self.addTab(self.AlertsTab)
|
||||||
|
|
||||||
def addTab(self, tab):
|
def addTab(self, tab):
|
||||||
log.info(u'Inserting %s' % tab.title())
|
log.info(u'Adding %s tab' % tab.title())
|
||||||
self.SettingsTabWidget.addTab(tab, tab.title())
|
return self.SettingsTabWidget.addTab(tab, tab.title())
|
||||||
|
|
||||||
|
def insertTab(self, id, tab):
|
||||||
|
log.debug(u'Inserting %s tab' % tab.title())
|
||||||
|
self.SettingsTabWidget.insertTab(id, tab, tab.title())
|
||||||
|
|
||||||
|
def removeTab(self, id):
|
||||||
|
log.debug(u'remove %s no tab' % unicode(id))
|
||||||
|
self.SettingsTabWidget.removeTab(id)
|
||||||
|
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
for tab_index in range(0, self.SettingsTabWidget.count()):
|
for tab_index in range(0, self.SettingsTabWidget.count()):
|
||||||
|
@ -28,7 +28,7 @@ import logging
|
|||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.lib import Plugin, Receiver, translate, str_to_bool, buildIcon
|
from openlp.core.lib import Plugin, Receiver, translate, str_to_bool, buildIcon
|
||||||
from openlp.plugins.audit.lib import AuditTab, AuditManager
|
from openlp.plugins.audit.lib import AuditManager
|
||||||
from openlp.plugins.audit.forms import AuditDetailForm, AuditDeleteForm
|
from openlp.plugins.audit.forms import AuditDetailForm, AuditDeleteForm
|
||||||
from openlp.plugins.audit.lib.models import AuditItem
|
from openlp.plugins.audit.lib.models import AuditItem
|
||||||
|
|
||||||
@ -43,18 +43,11 @@ class AuditPlugin(Plugin):
|
|||||||
self.weight = -4
|
self.weight = -4
|
||||||
# Create the plugin icon
|
# Create the plugin icon
|
||||||
self.icon = buildIcon(u':/media/media_image.png')
|
self.icon = buildIcon(u':/media/media_image.png')
|
||||||
self.auditfile = None
|
self.auditmanager = None
|
||||||
|
self.auditActive = False
|
||||||
|
|
||||||
def check_pre_conditions(self):
|
def can_be_disabled(self):
|
||||||
"""
|
return True
|
||||||
Check to see if auditing is required
|
|
||||||
"""
|
|
||||||
log.debug(u'check_pre_conditions')
|
|
||||||
#Lets see if audit is required
|
|
||||||
if int(self.config.get_config(u'startup', 0)) == QtCore.Qt.Checked:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def add_tools_menu_item(self, tools_menu):
|
def add_tools_menu_item(self, tools_menu):
|
||||||
"""
|
"""
|
||||||
@ -65,6 +58,8 @@ class AuditPlugin(Plugin):
|
|||||||
The actual **Tools** menu item, so that your actions can
|
The actual **Tools** menu item, so that your actions can
|
||||||
use it as their parent.
|
use it as their parent.
|
||||||
"""
|
"""
|
||||||
|
log.info(u'add tools menu')
|
||||||
|
self.toolsMenu = tools_menu
|
||||||
self.AuditMenu = QtGui.QMenu(tools_menu)
|
self.AuditMenu = QtGui.QMenu(tools_menu)
|
||||||
self.AuditMenu.setObjectName(u'AuditMenu')
|
self.AuditMenu.setObjectName(u'AuditMenu')
|
||||||
self.AuditMenu.setTitle(
|
self.AuditMenu.setTitle(
|
||||||
@ -102,7 +97,7 @@ class AuditPlugin(Plugin):
|
|||||||
self.AuditStatus.setShortcut(translate(u'AuditPlugin', u'F4'))
|
self.AuditStatus.setShortcut(translate(u'AuditPlugin', u'F4'))
|
||||||
self.AuditStatus.setObjectName(u'AuditStatus')
|
self.AuditStatus.setObjectName(u'AuditStatus')
|
||||||
#Add Menus together
|
#Add Menus together
|
||||||
tools_menu.addAction(self.AuditMenu.menuAction())
|
self.toolsMenu.addAction(self.AuditMenu.menuAction())
|
||||||
self.AuditMenu.addAction(self.AuditStatus)
|
self.AuditMenu.addAction(self.AuditStatus)
|
||||||
self.AuditMenu.addSeparator()
|
self.AuditMenu.addSeparator()
|
||||||
self.AuditMenu.addAction(self.AuditDeleteAll)
|
self.AuditMenu.addAction(self.AuditDeleteAll)
|
||||||
@ -122,13 +117,11 @@ class AuditPlugin(Plugin):
|
|||||||
QtCore.SIGNAL(u'triggered()'), self.onAuditDelete)
|
QtCore.SIGNAL(u'triggered()'), self.onAuditDelete)
|
||||||
QtCore.QObject.connect(self.AuditReport,
|
QtCore.QObject.connect(self.AuditReport,
|
||||||
QtCore.SIGNAL(u'triggered()'), self.onAuditReport)
|
QtCore.SIGNAL(u'triggered()'), self.onAuditReport)
|
||||||
|
self.AuditMenu.menuAction().setVisible(False)
|
||||||
def get_settings_tab(self):
|
|
||||||
self.AuditTab = AuditTab()
|
|
||||||
return self.AuditTab
|
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
log.info(u'Plugin Initialising')
|
log.info(u'audit Initialising')
|
||||||
|
Plugin.initialise(self)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'audit_live'), self.onReceiveAudit)
|
QtCore.SIGNAL(u'audit_live'), self.onReceiveAudit)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
@ -136,9 +129,17 @@ class AuditPlugin(Plugin):
|
|||||||
self.auditActive = str_to_bool(
|
self.auditActive = str_to_bool(
|
||||||
self.config.get_config(u'audit active', False))
|
self.config.get_config(u'audit active', False))
|
||||||
self.AuditStatus.setChecked(self.auditActive)
|
self.AuditStatus.setChecked(self.auditActive)
|
||||||
self.auditmanager = AuditManager(self.config)
|
if self.auditmanager is None:
|
||||||
|
self.auditmanager = AuditManager(self.config)
|
||||||
self.auditdeleteform = AuditDeleteForm(self.auditmanager)
|
self.auditdeleteform = AuditDeleteForm(self.auditmanager)
|
||||||
self.auditdetailform = AuditDetailForm(self.auditmanager)
|
self.auditdetailform = AuditDetailForm(self.auditmanager)
|
||||||
|
self.AuditMenu.menuAction().setVisible(True)
|
||||||
|
|
||||||
|
def finalise(self):
|
||||||
|
log.info(u'Plugin Finalise')
|
||||||
|
self.AuditMenu.menuAction().setVisible(False)
|
||||||
|
#stop any events being processed
|
||||||
|
self.auditActive = False
|
||||||
|
|
||||||
def toggleAuditState(self):
|
def toggleAuditState(self):
|
||||||
self.auditActive = not self.auditActive
|
self.auditActive = not self.auditActive
|
||||||
|
@ -22,5 +22,4 @@
|
|||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
from audittab import AuditTab
|
|
||||||
from manager import AuditManager
|
from manager import AuditManager
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2009 Raoul Snyman #
|
|
||||||
# Portions copyright (c) 2008-2009 Martin Thompson, Tim Bentley, Carsten #
|
|
||||||
# Tinggaard, Jon Tibble, Jonathan Corwin, Maikel Stuivenberg, Scott Guerrieri #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# This program is free software; you can redistribute it and/or modify it #
|
|
||||||
# under the terms of the GNU General Public License as published by the Free #
|
|
||||||
# Software Foundation; version 2 of the License. #
|
|
||||||
# #
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
|
||||||
# more details. #
|
|
||||||
# #
|
|
||||||
# You should have received a copy of the GNU General Public License along #
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
from PyQt4 import QtGui
|
|
||||||
|
|
||||||
from openlp.core.lib import SettingsTab, translate, Receiver
|
|
||||||
|
|
||||||
class AuditTab(SettingsTab):
|
|
||||||
"""
|
|
||||||
AuditTab is the Audit settings tab in the settings dialog.
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
SettingsTab.__init__(self, translate(u'AuditTab', u'Audit'), u'Audit')
|
|
||||||
|
|
||||||
def setupUi(self):
|
|
||||||
self.setObjectName(u'AuditTab')
|
|
||||||
self.AuditModeGroupBox = QtGui.QGroupBox(self)
|
|
||||||
self.AuditModeGroupBox.setObjectName(u'AuditModeGroupBox')
|
|
||||||
self.verticalLayout = QtGui.QVBoxLayout(self.AuditModeGroupBox)
|
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
|
||||||
self.AuditActive = QtGui.QCheckBox(self)
|
|
||||||
self.AuditActive.setObjectName("AuditActive")
|
|
||||||
self.verticalLayout.addWidget(self.AuditActive)
|
|
||||||
self.WarningLabel = QtGui.QLabel(self)
|
|
||||||
self.WarningLabel.setObjectName("WarningLabel")
|
|
||||||
self.verticalLayout.addWidget(self.WarningLabel)
|
|
||||||
|
|
||||||
def retranslateUi(self):
|
|
||||||
self.AuditModeGroupBox.setTitle(translate(u'AuditTab', u'Audit File'))
|
|
||||||
self.AuditActive.setText(translate(u'AuditTab', 'Audit available:'))
|
|
||||||
self.WarningLabel.setText(translate(u'AuditTab',
|
|
||||||
u'A restart is needed for this change to become effective'))
|
|
||||||
|
|
||||||
def load(self):
|
|
||||||
self.AuditActive.setChecked(int(self.config.get_config(u'startup', 0)))
|
|
||||||
|
|
||||||
def save(self):
|
|
||||||
self.config.set_config(
|
|
||||||
u'startup', unicode(self.AuditActive.checkState()))
|
|
||||||
Receiver().send_message(u'audit_changed')
|
|
@ -44,13 +44,11 @@ class BiblePlugin(Plugin):
|
|||||||
self.biblemanager = BibleManager(self.config)
|
self.biblemanager = BibleManager(self.config)
|
||||||
|
|
||||||
def get_settings_tab(self):
|
def get_settings_tab(self):
|
||||||
self.bibles_tab = BiblesTab()
|
return BiblesTab()
|
||||||
return self.bibles_tab
|
|
||||||
|
|
||||||
def get_media_manager_item(self):
|
def get_media_manager_item(self):
|
||||||
# Create the BibleManagerItem object
|
# Create the BibleManagerItem object
|
||||||
self.media_item = BibleMediaItem(self, self.icon, u'Bible Verses')
|
return BibleMediaItem(self, self.icon, u'Bible Verses')
|
||||||
return self.media_item
|
|
||||||
|
|
||||||
def add_import_menu_item(self, import_menu):
|
def add_import_menu_item(self, import_menu):
|
||||||
self.ImportBibleItem = QtGui.QAction(import_menu)
|
self.ImportBibleItem = QtGui.QAction(import_menu)
|
||||||
|
@ -54,8 +54,7 @@ class CustomPlugin(Plugin):
|
|||||||
|
|
||||||
def get_media_manager_item(self):
|
def get_media_manager_item(self):
|
||||||
# Create the CustomManagerItem object
|
# Create the CustomManagerItem object
|
||||||
self.media_item = CustomMediaItem(self, self.icon, u'Custom Slides')
|
return CustomMediaItem(self, self.icon, u'Custom Slides')
|
||||||
return self.media_item
|
|
||||||
|
|
||||||
def about(self):
|
def about(self):
|
||||||
return u'<b>Custom Plugin</b> <br>This plugin allows slides to be displayed on the screen in the same way songs are. The difference between this plugin and songs is this plugin provides greater freedom.<br><br>This is a core plugin and cannot be made inactive</b>'
|
return u'<b>Custom Plugin</b> <br>This plugin allows slides to be displayed on the screen in the same way songs are. The difference between this plugin and songs is this plugin provides greater freedom.<br><br>This is a core plugin and cannot be made inactive</b>'
|
||||||
|
@ -39,14 +39,24 @@ class ImagePlugin(Plugin):
|
|||||||
# Create the plugin icon
|
# Create the plugin icon
|
||||||
self.icon = buildIcon(u':/media/media_image.png')
|
self.icon = buildIcon(u':/media/media_image.png')
|
||||||
|
|
||||||
|
def can_be_disabled(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def initialise(self):
|
||||||
|
log.info(u'Plugin Initialising')
|
||||||
|
Plugin.initialise(self)
|
||||||
|
self.insert_toolbox_item()
|
||||||
|
|
||||||
|
def finalise(self):
|
||||||
|
log.info(u'Plugin Finalise')
|
||||||
|
self.remove_toolbox_item()
|
||||||
|
|
||||||
def get_settings_tab(self):
|
def get_settings_tab(self):
|
||||||
self.ImageTab = ImageTab()
|
return ImageTab()
|
||||||
return self.ImageTab
|
|
||||||
|
|
||||||
def get_media_manager_item(self):
|
def get_media_manager_item(self):
|
||||||
# Create the MediaManagerItem object
|
# Create the MediaManagerItem object
|
||||||
self.media_item = ImageMediaItem(self, self.icon, u'Images')
|
return ImageMediaItem(self, self.icon, u'Images')
|
||||||
return self.media_item
|
|
||||||
|
|
||||||
def about(self):
|
def about(self):
|
||||||
return u'<b>Image Plugin</b><br>Allows images of all types to be displayed. If a number of images are selected together and presented on the live controller it is possible to turn them into a timed loop.<br> From the plugin if the <i>Override background</i> is chosen and an image is selected any somgs which are rendered will use the selected image from the background instead of the one provied by the theme.<br>'
|
return u'<b>Image Plugin</b><br>Allows images of all types to be displayed. If a number of images are selected together and presented on the live controller it is possible to turn them into a timed loop.<br> From the plugin if the <i>Override background</i> is chosen and an image is selected any somgs which are rendered will use the selected image from the background instead of the one provied by the theme.<br>'
|
||||||
|
@ -65,6 +65,8 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
self.hasEditIcon = False
|
self.hasEditIcon = False
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
|
log.debug(u'initialise')
|
||||||
|
self.ListView.clear()
|
||||||
self.ListView.setSelectionMode(
|
self.ListView.setSelectionMode(
|
||||||
QtGui.QAbstractItemView.ExtendedSelection)
|
QtGui.QAbstractItemView.ExtendedSelection)
|
||||||
self.ListView.setIconSize(QtCore.QSize(88,50))
|
self.ListView.setIconSize(QtCore.QSize(88,50))
|
||||||
|
@ -37,13 +37,11 @@ class MediaPlugin(Plugin):
|
|||||||
self.dnd_id = u'Media'
|
self.dnd_id = u'Media'
|
||||||
|
|
||||||
def get_settings_tab(self):
|
def get_settings_tab(self):
|
||||||
self.MediaTab = MediaTab()
|
return MediaTab()
|
||||||
return self.MediaTab
|
|
||||||
|
|
||||||
def get_media_manager_item(self):
|
def get_media_manager_item(self):
|
||||||
# Create the MediaManagerItem object
|
# Create the MediaManagerItem object
|
||||||
self.media_item = MediaMediaItem(self, self.icon, u'Media')
|
return MediaMediaItem(self, self.icon, u'Media')
|
||||||
return self.media_item
|
|
||||||
|
|
||||||
def about(self):
|
def about(self):
|
||||||
return u'<b>Media Plugin</b> <br> One day this may provide access to video and audio clips'
|
return u'<b>Media Plugin</b> <br> One day this may provide access to video and audio clips'
|
||||||
|
@ -50,16 +50,14 @@ class PresentationPlugin(Plugin):
|
|||||||
"""
|
"""
|
||||||
Create the settings Tab
|
Create the settings Tab
|
||||||
"""
|
"""
|
||||||
self.presentation_tab = PresentationTab(self.controllers)
|
return PresentationTab(self.controllers)
|
||||||
return self.presentation_tab
|
|
||||||
|
|
||||||
def get_media_manager_item(self):
|
def get_media_manager_item(self):
|
||||||
"""
|
"""
|
||||||
Create the Media Manager List
|
Create the Media Manager List
|
||||||
"""
|
"""
|
||||||
self.media_item = PresentationMediaItem(
|
return PresentationMediaItem(
|
||||||
self, self.icon, u'Presentations', self.controllers)
|
self, self.icon, u'Presentations', self.controllers)
|
||||||
return self.media_item
|
|
||||||
|
|
||||||
def registerControllers(self, controller):
|
def registerControllers(self, controller):
|
||||||
self.controllers[controller.name] = controller
|
self.controllers[controller.name] = controller
|
||||||
|
@ -44,31 +44,17 @@ class RemoteTab(SettingsTab):
|
|||||||
self.RemotePortSpinBox.setObjectName(u'RemotePortSpinBox')
|
self.RemotePortSpinBox.setObjectName(u'RemotePortSpinBox')
|
||||||
self.RemotePortSpinBox.setMaximum(32767)
|
self.RemotePortSpinBox.setMaximum(32767)
|
||||||
self.RemoteModeLayout.addWidget(self.RemotePortSpinBox)
|
self.RemoteModeLayout.addWidget(self.RemotePortSpinBox)
|
||||||
self.RemoteActive = QtGui.QCheckBox(self.RemoteModeGroupBox)
|
|
||||||
self.RemoteActive.setObjectName(u'RemotePortSpinBox')
|
|
||||||
self.RemoteModeLayout.addWidget(self.RemoteActive)
|
|
||||||
self.WarningLabel = QtGui.QLabel(self.RemoteModeGroupBox)
|
|
||||||
self.WarningLabel.setObjectName(u'WarningLabel')
|
|
||||||
self.RemoteModeLayout.addWidget(self.WarningLabel)
|
|
||||||
self.RemoteLayout.setWidget(
|
self.RemoteLayout.setWidget(
|
||||||
0, QtGui.QFormLayout.LabelRole, self.RemoteModeGroupBox)
|
0, QtGui.QFormLayout.LabelRole, self.RemoteModeGroupBox)
|
||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
self.RemoteModeGroupBox.setTitle(
|
self.RemoteModeGroupBox.setTitle(
|
||||||
translate(u'RemoteTab', u'Remotes Receiver Port'))
|
translate(u'RemoteTab', u'Remotes Receiver Port'))
|
||||||
self.RemoteActive.setText(translate(u'RemoteTab', 'Remote available:'))
|
|
||||||
self.WarningLabel.setText(translate(u'RemoteTab',
|
|
||||||
u'A restart is needed for this change to become effective'))
|
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
self.RemotePortSpinBox.setValue(
|
self.RemotePortSpinBox.setValue(
|
||||||
int(self.config.get_config(u'remote port', 4316)))
|
int(self.config.get_config(u'remote port', 4316)))
|
||||||
self.RemoteActive.setChecked(
|
|
||||||
int(self.config.get_config(u'startup', 0)))
|
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
self.config.set_config(
|
self.config.set_config(
|
||||||
u'remote port', unicode(self.RemotePortSpinBox.value()))
|
u'remote port', unicode(self.RemotePortSpinBox.value()))
|
||||||
self.config.set_config(
|
|
||||||
u'startup', unicode(self.RemoteActive.checkState()))
|
|
||||||
|
|
||||||
|
@ -34,29 +34,22 @@ class RemotesPlugin(Plugin):
|
|||||||
# Call the parent constructor
|
# Call the parent constructor
|
||||||
Plugin.__init__(self, u'Remotes', u'1.9.0', plugin_helpers)
|
Plugin.__init__(self, u'Remotes', u'1.9.0', plugin_helpers)
|
||||||
self.weight = -1
|
self.weight = -1
|
||||||
|
self.server = None
|
||||||
|
|
||||||
def can_be_disabled(self):
|
def can_be_disabled(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def check_pre_conditions(self):
|
|
||||||
"""
|
|
||||||
Check to see if remotes is required
|
|
||||||
"""
|
|
||||||
log.debug(u'check_pre_conditions')
|
|
||||||
#Lets see if Remote is required
|
|
||||||
if int(self.config.get_config(u'startup', 0)) == QtCore.Qt.Checked:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
|
log.debug(u'initialise')
|
||||||
self.server = QtNetwork.QUdpSocket()
|
self.server = QtNetwork.QUdpSocket()
|
||||||
self.server.bind(int(self.config.get_config(u'remote port', 4316)))
|
self.server.bind(int(self.config.get_config(u'remote port', 4316)))
|
||||||
QtCore.QObject.connect(self.server,
|
QtCore.QObject.connect(self.server,
|
||||||
QtCore.SIGNAL(u'readyRead()'), self.readData)
|
QtCore.SIGNAL(u'readyRead()'), self.readData)
|
||||||
|
|
||||||
def finalise(self):
|
def finalise(self):
|
||||||
pass
|
log.debug(u'finalise')
|
||||||
|
if self.server is not None:
|
||||||
|
self.server.close()
|
||||||
|
|
||||||
def about(self):
|
def about(self):
|
||||||
return u'<b>Remote Plugin</b> <br>This plugin provides the ability to send messages to a running version of openlp on a different computer.<br> The Primary use for this would be to send alerts from a creche'
|
return u'<b>Remote Plugin</b> <br>This plugin provides the ability to send messages to a running version of openlp on a different computer.<br> The Primary use for this would be to send alerts from a creche'
|
||||||
@ -78,11 +71,7 @@ class RemotesPlugin(Plugin):
|
|||||||
log.info(u'Sending event %s ', datagram)
|
log.info(u'Sending event %s ', datagram)
|
||||||
pos = datagram.find(u':')
|
pos = datagram.find(u':')
|
||||||
event = unicode(datagram[:pos].lower())
|
event = unicode(datagram[:pos].lower())
|
||||||
|
|
||||||
if event == u'alert':
|
if event == u'alert':
|
||||||
Receiver().send_message(u'alert_text', unicode(datagram[pos + 1:]))
|
Receiver().send_message(u'alert_text', unicode(datagram[pos + 1:]))
|
||||||
if event == u'next_slide':
|
if event == u'next_slide':
|
||||||
Receiver().send_message(u'live_slide_next')
|
Receiver().send_message(u'live_slide_next')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -64,8 +64,7 @@ class SongsPlugin(Plugin):
|
|||||||
Create the MediaManagerItem object, which is displaed in the
|
Create the MediaManagerItem object, which is displaed in the
|
||||||
Media Manager.
|
Media Manager.
|
||||||
"""
|
"""
|
||||||
self.media_item = SongMediaItem(self, self.icon, 'Songs')
|
return SongMediaItem(self, self.icon, 'Songs')
|
||||||
return self.media_item
|
|
||||||
|
|
||||||
def add_import_menu_item(self, import_menu):
|
def add_import_menu_item(self, import_menu):
|
||||||
"""
|
"""
|
||||||
@ -146,6 +145,7 @@ class SongsPlugin(Plugin):
|
|||||||
QtCore.SIGNAL(u'triggered()'), self.onExportOpenSongItemClicked)
|
QtCore.SIGNAL(u'triggered()'), self.onExportOpenSongItemClicked)
|
||||||
|
|
||||||
def initialise(self):
|
def initialise(self):
|
||||||
|
Plugin.initialise(self)
|
||||||
self.media_item.displayResultsSong(self.songmanager.get_songs())
|
self.media_item.displayResultsSong(self.songmanager.get_songs())
|
||||||
|
|
||||||
def onImportOpenlp1ItemClick(self):
|
def onImportOpenlp1ItemClick(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user