forked from openlp/openlp
r1242
This commit is contained in:
commit
b6a4bf4277
@ -243,7 +243,7 @@ class ServiceItem(object):
|
||||
file to represent this item.
|
||||
"""
|
||||
service_header = {
|
||||
u'name': self.name.lower(),
|
||||
u'name': self.name,
|
||||
u'plugin': self.name,
|
||||
u'theme': self.theme,
|
||||
u'title': self.title,
|
||||
@ -392,10 +392,16 @@ class ServiceItem(object):
|
||||
"""
|
||||
Returns the title of the raw frame
|
||||
"""
|
||||
return self._raw_frames[row][u'title']
|
||||
try:
|
||||
return self._raw_frames[row][u'title']
|
||||
except IndexError:
|
||||
return u''
|
||||
|
||||
def get_frame_path(self, row=0):
|
||||
"""
|
||||
Returns the path of the raw frame
|
||||
"""
|
||||
return self._raw_frames[row][u'path']
|
||||
try:
|
||||
return self._raw_frames[row][u'path']
|
||||
except IndexError:
|
||||
return u''
|
||||
|
@ -261,7 +261,7 @@ class ThemeXML(object):
|
||||
def add_font(self, name, color, size, override, fonttype=u'main',
|
||||
bold=u'False', italics=u'False', line_adjustment=0,
|
||||
xpos=0, ypos=0, width=0, height=0 , outline=u'False',
|
||||
outline_color=u'#ffffff', outline_pixel=2, shadow=u'False',
|
||||
outline_color=u'#ffffff', outline_pixel=2, shadow=u'False',
|
||||
shadow_color=u'#ffffff', shadow_pixel=5):
|
||||
"""
|
||||
Add a Font.
|
||||
|
@ -51,7 +51,8 @@ class OpenLPToolbar(QtGui.QToolBar):
|
||||
log.debug(u'Init done')
|
||||
|
||||
def addToolbarButton(self, title, icon, tooltip=None, slot=None,
|
||||
checkable=False):
|
||||
checkable=False, shortcut=0, alternate=0,
|
||||
context=QtCore.Qt.WidgetShortcut):
|
||||
"""
|
||||
A method to help developers easily add a button to the toolbar.
|
||||
|
||||
@ -72,6 +73,15 @@ class OpenLPToolbar(QtGui.QToolBar):
|
||||
``checkable``
|
||||
If *True* the button has two, *off* and *on*, states. Default is
|
||||
*False*, which means the buttons has only one state.
|
||||
|
||||
``shortcut``
|
||||
The primary shortcut for this action
|
||||
|
||||
``alternate``
|
||||
The alternate shortcut for this action
|
||||
|
||||
``context``
|
||||
Specify the context in which this shortcut is valid
|
||||
"""
|
||||
newAction = None
|
||||
if icon:
|
||||
@ -93,6 +103,8 @@ class OpenLPToolbar(QtGui.QToolBar):
|
||||
QtCore.QObject.connect(newAction,
|
||||
QtCore.SIGNAL(u'toggled(bool)'), slot)
|
||||
self.actions[title] = newAction
|
||||
newAction.setShortcuts([shortcut, alternate])
|
||||
newAction.setShortcutContext(context)
|
||||
return newAction
|
||||
|
||||
def addToolbarSeparator(self, handle):
|
||||
|
@ -54,45 +54,6 @@ class DisplayWidget(QtGui.QGraphicsView):
|
||||
QtGui.QGraphicsView.__init__(self)
|
||||
self.parent = parent
|
||||
self.live = live
|
||||
self.hotkey_map = {
|
||||
QtCore.Qt.Key_Return: 'servicemanager_next_item',
|
||||
QtCore.Qt.Key_Space: 'slidecontroller_live_next_noloop',
|
||||
QtCore.Qt.Key_Enter: 'slidecontroller_live_next_noloop',
|
||||
QtCore.Qt.Key_0: 'servicemanager_next_item',
|
||||
QtCore.Qt.Key_Backspace: 'slidecontroller_live_previous_noloop'}
|
||||
self.setStyleSheet(u'border: none;')
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
"""
|
||||
Handle key events from display screen
|
||||
"""
|
||||
# Key events only needed for live
|
||||
if not self.live:
|
||||
return
|
||||
if isinstance(event, QtGui.QKeyEvent):
|
||||
# Here accept the event and do something
|
||||
if event.key() == QtCore.Qt.Key_Up:
|
||||
Receiver.send_message(u'slidecontroller_live_previous')
|
||||
event.accept()
|
||||
elif event.key() == QtCore.Qt.Key_Down:
|
||||
Receiver.send_message(u'slidecontroller_live_next')
|
||||
event.accept()
|
||||
elif event.key() == QtCore.Qt.Key_PageUp:
|
||||
Receiver.send_message(u'slidecontroller_live_first')
|
||||
event.accept()
|
||||
elif event.key() == QtCore.Qt.Key_PageDown:
|
||||
Receiver.send_message(u'slidecontroller_live_last')
|
||||
event.accept()
|
||||
elif event.key() in self.hotkey_map:
|
||||
Receiver.send_message(self.hotkey_map[event.key()])
|
||||
event.accept()
|
||||
elif event.key() == QtCore.Qt.Key_Escape:
|
||||
self.setVisible(False)
|
||||
self.videoStop()
|
||||
event.accept()
|
||||
event.ignore()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
|
||||
class MainDisplay(DisplayWidget):
|
||||
@ -176,11 +137,10 @@ class MainDisplay(DisplayWidget):
|
||||
painter_image.begin(initialFrame)
|
||||
painter_image.fillRect(initialFrame.rect(), QtCore.Qt.white)
|
||||
painter_image.drawImage(
|
||||
(self.screens.current[u'size'].width() \
|
||||
- splash_image.width()) / 2,
|
||||
(self.screens.current[u'size'].height() \
|
||||
- splash_image.height()) / 2,
|
||||
splash_image)
|
||||
(self.screens.current[u'size'].width() -
|
||||
splash_image.width()) / 2,
|
||||
(self.screens.current[u'size'].height()
|
||||
- splash_image.height()) / 2, splash_image)
|
||||
serviceItem = ServiceItem()
|
||||
serviceItem.bg_image_bytes = image_to_byte(initialFrame)
|
||||
self.webView.setHtml(build_html(serviceItem, self.screen,
|
||||
@ -280,7 +240,10 @@ class MainDisplay(DisplayWidget):
|
||||
Used after Image plugin has changed the background
|
||||
"""
|
||||
log.debug(u'resetImage')
|
||||
self.displayImage(self.serviceItem.bg_image_bytes)
|
||||
if hasattr(self, u'serviceItem'):
|
||||
self.displayImage(self.serviceItem.bg_image_bytes)
|
||||
else:
|
||||
self.displayImage(None)
|
||||
# Update the preview frame.
|
||||
Receiver.send_message(u'maindisplay_active')
|
||||
|
||||
@ -382,13 +345,11 @@ class MainDisplay(DisplayWidget):
|
||||
Generates a preview of the image displayed.
|
||||
"""
|
||||
log.debug(u'preview for %s', self.isLive)
|
||||
# We must have a service item to preview
|
||||
if not hasattr(self, u'serviceItem'):
|
||||
return
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
if self.isLive:
|
||||
# We must have a service item to preview
|
||||
if self.isLive and hasattr(self, u'serviceItem'):
|
||||
# Wait for the fade to finish before geting the preview.
|
||||
# Important otherwise preview will have incorrect text if at all !
|
||||
# Important otherwise preview will have incorrect text if at all!
|
||||
if self.serviceItem.themedata and \
|
||||
self.serviceItem.themedata.display_slide_transition:
|
||||
while self.frame.evaluateJavaScript(u'show_text_complete()') \
|
||||
@ -401,9 +362,8 @@ class MainDisplay(DisplayWidget):
|
||||
# if was hidden keep it hidden
|
||||
if self.isLive:
|
||||
self.setVisible(True)
|
||||
# if was hidden keep it hidden
|
||||
if self.hideMode and self.isLive:
|
||||
self.hideDisplay(self.hideMode)
|
||||
if self.hideMode:
|
||||
self.hideDisplay(self.hideMode)
|
||||
preview = QtGui.QImage(self.screen[u'size'].width(),
|
||||
self.screen[u'size'].height(),
|
||||
QtGui.QImage.Format_ARGB32_Premultiplied)
|
||||
@ -437,7 +397,8 @@ class MainDisplay(DisplayWidget):
|
||||
self.hideDisplay(self.hideMode)
|
||||
# Hide mouse cursor when moved over display if enabled in settings
|
||||
settings = QtCore.QSettings()
|
||||
if settings.value(u'advanced/hide mouse', QtCore.QVariant(False)).toBool():
|
||||
if settings.value(u'advanced/hide mouse',
|
||||
QtCore.QVariant(False)).toBool():
|
||||
self.setCursor(QtCore.Qt.BlankCursor)
|
||||
self.frame.evaluateJavaScript('document.body.style.cursor = "none"')
|
||||
else:
|
||||
|
@ -59,23 +59,23 @@ MEDIA_MANAGER_STYLE = """
|
||||
"""
|
||||
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
def setupUi(self, mainWindow):
|
||||
"""
|
||||
Set up the user interface
|
||||
"""
|
||||
MainWindow.setObjectName(u'MainWindow')
|
||||
MainWindow.resize(self.settingsmanager.width,
|
||||
mainWindow.setObjectName(u'MainWindow')
|
||||
mainWindow.resize(self.settingsmanager.width,
|
||||
self.settingsmanager.height)
|
||||
MainWindow.setWindowIcon(build_icon(u':/icon/openlp-logo-16x16.png'))
|
||||
MainWindow.setDockNestingEnabled(True)
|
||||
mainWindow.setWindowIcon(build_icon(u':/icon/openlp-logo-16x16.png'))
|
||||
mainWindow.setDockNestingEnabled(True)
|
||||
# Set up the main container, which contains all the other form widgets.
|
||||
self.MainContent = QtGui.QWidget(MainWindow)
|
||||
self.MainContent = QtGui.QWidget(mainWindow)
|
||||
self.MainContent.setObjectName(u'MainContent')
|
||||
self.MainContentLayout = QtGui.QHBoxLayout(self.MainContent)
|
||||
self.MainContentLayout.setSpacing(0)
|
||||
self.MainContentLayout.setMargin(0)
|
||||
self.MainContentLayout.setObjectName(u'MainContentLayout')
|
||||
MainWindow.setCentralWidget(self.MainContent)
|
||||
mainWindow.setCentralWidget(self.MainContent)
|
||||
self.ControlSplitter = QtGui.QSplitter(self.MainContent)
|
||||
self.ControlSplitter.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.ControlSplitter.setObjectName(u'ControlSplitter')
|
||||
@ -92,7 +92,7 @@ class Ui_MainWindow(object):
|
||||
QtCore.QVariant(True)).toBool()
|
||||
self.liveController.Panel.setVisible(liveVisible)
|
||||
# Create menu
|
||||
self.MenuBar = QtGui.QMenuBar(MainWindow)
|
||||
self.MenuBar = QtGui.QMenuBar(mainWindow)
|
||||
self.MenuBar.setObjectName(u'MenuBar')
|
||||
self.FileMenu = QtGui.QMenu(self.MenuBar)
|
||||
self.FileMenu.setObjectName(u'FileMenu')
|
||||
@ -116,16 +116,16 @@ class Ui_MainWindow(object):
|
||||
# Help Menu
|
||||
self.HelpMenu = QtGui.QMenu(self.MenuBar)
|
||||
self.HelpMenu.setObjectName(u'HelpMenu')
|
||||
MainWindow.setMenuBar(self.MenuBar)
|
||||
self.StatusBar = QtGui.QStatusBar(MainWindow)
|
||||
mainWindow.setMenuBar(self.MenuBar)
|
||||
self.StatusBar = QtGui.QStatusBar(mainWindow)
|
||||
self.StatusBar.setObjectName(u'StatusBar')
|
||||
MainWindow.setStatusBar(self.StatusBar)
|
||||
mainWindow.setStatusBar(self.StatusBar)
|
||||
self.DefaultThemeLabel = QtGui.QLabel(self.StatusBar)
|
||||
self.DefaultThemeLabel.setObjectName(u'DefaultThemeLabel')
|
||||
self.StatusBar.addPermanentWidget(self.DefaultThemeLabel)
|
||||
# Create the MediaManager
|
||||
self.MediaManagerDock = OpenLPDockWidget(
|
||||
MainWindow, u'MediaManagerDock',
|
||||
mainWindow, u'MediaManagerDock',
|
||||
build_icon(u':/system/system_mediamanager.png'))
|
||||
self.MediaManagerDock.setStyleSheet(MEDIA_MANAGER_STYLE)
|
||||
self.MediaManagerDock.setMinimumWidth(
|
||||
@ -134,127 +134,127 @@ class Ui_MainWindow(object):
|
||||
self.MediaToolBox = QtGui.QToolBox(self.MediaManagerDock)
|
||||
self.MediaToolBox.setObjectName(u'MediaToolBox')
|
||||
self.MediaManagerDock.setWidget(self.MediaToolBox)
|
||||
MainWindow.addDockWidget(QtCore.Qt.LeftDockWidgetArea,
|
||||
mainWindow.addDockWidget(QtCore.Qt.LeftDockWidgetArea,
|
||||
self.MediaManagerDock)
|
||||
# Create the service manager
|
||||
self.ServiceManagerDock = OpenLPDockWidget(
|
||||
MainWindow, u'ServiceManagerDock',
|
||||
mainWindow, u'ServiceManagerDock',
|
||||
build_icon(u':/system/system_servicemanager.png'))
|
||||
self.ServiceManagerDock.setMinimumWidth(
|
||||
self.settingsmanager.mainwindow_right)
|
||||
self.ServiceManagerContents = ServiceManager(MainWindow,
|
||||
self.ServiceManagerContents = ServiceManager(mainWindow,
|
||||
self.ServiceManagerDock)
|
||||
self.ServiceManagerDock.setWidget(self.ServiceManagerContents)
|
||||
MainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea,
|
||||
mainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea,
|
||||
self.ServiceManagerDock)
|
||||
# Create the theme manager
|
||||
self.ThemeManagerDock = OpenLPDockWidget(
|
||||
MainWindow, u'ThemeManagerDock',
|
||||
mainWindow, u'ThemeManagerDock',
|
||||
build_icon(u':/system/system_thememanager.png'))
|
||||
self.ThemeManagerDock.setMinimumWidth(
|
||||
self.settingsmanager.mainwindow_right)
|
||||
self.ThemeManagerContents = ThemeManager(MainWindow,
|
||||
self.ThemeManagerContents = ThemeManager(mainWindow,
|
||||
self.ThemeManagerDock)
|
||||
self.ThemeManagerContents.setObjectName(u'ThemeManagerContents')
|
||||
self.ThemeManagerDock.setWidget(self.ThemeManagerContents)
|
||||
MainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea,
|
||||
mainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea,
|
||||
self.ThemeManagerDock)
|
||||
# Create the menu items
|
||||
self.FileNewItem = QtGui.QAction(MainWindow)
|
||||
self.FileNewItem = QtGui.QAction(mainWindow)
|
||||
self.FileNewItem.setIcon(build_icon(u':/general/general_new.png'))
|
||||
self.FileNewItem.setObjectName(u'FileNewItem')
|
||||
MainWindow.actionList.add_action(self.FileNewItem, u'File')
|
||||
self.FileOpenItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.FileNewItem, u'File')
|
||||
self.FileOpenItem = QtGui.QAction(mainWindow)
|
||||
self.FileOpenItem.setIcon(build_icon(u':/general/general_open.png'))
|
||||
self.FileOpenItem.setObjectName(u'FileOpenItem')
|
||||
MainWindow.actionList.add_action(self.FileOpenItem, u'File')
|
||||
self.FileSaveItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.FileOpenItem, u'File')
|
||||
self.FileSaveItem = QtGui.QAction(mainWindow)
|
||||
self.FileSaveItem.setIcon(build_icon(u':/general/general_save.png'))
|
||||
self.FileSaveItem.setObjectName(u'FileSaveItem')
|
||||
MainWindow.actionList.add_action(self.FileSaveItem, u'File')
|
||||
self.FileSaveAsItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.FileSaveItem, u'File')
|
||||
self.FileSaveAsItem = QtGui.QAction(mainWindow)
|
||||
self.FileSaveAsItem.setObjectName(u'FileSaveAsItem')
|
||||
MainWindow.actionList.add_action(self.FileSaveAsItem, u'File')
|
||||
self.FileExitItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.FileSaveAsItem, u'File')
|
||||
self.FileExitItem = QtGui.QAction(mainWindow)
|
||||
self.FileExitItem.setIcon(build_icon(u':/system/system_exit.png'))
|
||||
self.FileExitItem.setObjectName(u'FileExitItem')
|
||||
MainWindow.actionList.add_action(self.FileExitItem, u'File')
|
||||
self.ImportThemeItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.FileExitItem, u'File')
|
||||
self.ImportThemeItem = QtGui.QAction(mainWindow)
|
||||
self.ImportThemeItem.setObjectName(u'ImportThemeItem')
|
||||
MainWindow.actionList.add_action(self.ImportThemeItem, u'Import')
|
||||
self.ImportLanguageItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.ImportThemeItem, u'Import')
|
||||
self.ImportLanguageItem = QtGui.QAction(mainWindow)
|
||||
self.ImportLanguageItem.setObjectName(u'ImportLanguageItem')
|
||||
MainWindow.actionList.add_action(self.ImportLanguageItem, u'Import')
|
||||
self.ExportThemeItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.ImportLanguageItem, u'Import')
|
||||
self.ExportThemeItem = QtGui.QAction(mainWindow)
|
||||
self.ExportThemeItem.setObjectName(u'ExportThemeItem')
|
||||
MainWindow.actionList.add_action(self.ExportThemeItem, u'Export')
|
||||
self.ExportLanguageItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.ExportThemeItem, u'Export')
|
||||
self.ExportLanguageItem = QtGui.QAction(mainWindow)
|
||||
self.ExportLanguageItem.setObjectName(u'ExportLanguageItem')
|
||||
MainWindow.actionList.add_action(self.ExportLanguageItem, u'Export')
|
||||
self.ViewMediaManagerItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.ExportLanguageItem, u'Export')
|
||||
self.ViewMediaManagerItem = QtGui.QAction(mainWindow)
|
||||
self.ViewMediaManagerItem.setCheckable(True)
|
||||
self.ViewMediaManagerItem.setChecked(self.MediaManagerDock.isVisible())
|
||||
self.ViewMediaManagerItem.setIcon(
|
||||
build_icon(u':/system/system_mediamanager.png'))
|
||||
self.ViewMediaManagerItem.setObjectName(u'ViewMediaManagerItem')
|
||||
self.ViewThemeManagerItem = QtGui.QAction(MainWindow)
|
||||
self.ViewThemeManagerItem = QtGui.QAction(mainWindow)
|
||||
self.ViewThemeManagerItem.setCheckable(True)
|
||||
self.ViewThemeManagerItem.setChecked(self.ThemeManagerDock.isVisible())
|
||||
self.ViewThemeManagerItem.setIcon(
|
||||
build_icon(u':/system/system_thememanager.png'))
|
||||
self.ViewThemeManagerItem.setObjectName(u'ViewThemeManagerItem')
|
||||
MainWindow.actionList.add_action(self.ViewMediaManagerItem, u'View')
|
||||
self.ViewServiceManagerItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.ViewMediaManagerItem, u'View')
|
||||
self.ViewServiceManagerItem = QtGui.QAction(mainWindow)
|
||||
self.ViewServiceManagerItem.setCheckable(True)
|
||||
self.ViewServiceManagerItem.setChecked(
|
||||
self.ServiceManagerDock.isVisible())
|
||||
self.ViewServiceManagerItem.setIcon(
|
||||
build_icon(u':/system/system_servicemanager.png'))
|
||||
self.ViewServiceManagerItem.setObjectName(u'ViewServiceManagerItem')
|
||||
MainWindow.actionList.add_action(self.ViewServiceManagerItem, u'View')
|
||||
self.ViewPreviewPanel = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.ViewServiceManagerItem, u'View')
|
||||
self.ViewPreviewPanel = QtGui.QAction(mainWindow)
|
||||
self.ViewPreviewPanel.setCheckable(True)
|
||||
self.ViewPreviewPanel.setChecked(previewVisible)
|
||||
self.ViewPreviewPanel.setObjectName(u'ViewPreviewPanel')
|
||||
MainWindow.actionList.add_action(self.ViewPreviewPanel, u'View')
|
||||
self.ViewLivePanel = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.ViewPreviewPanel, u'View')
|
||||
self.ViewLivePanel = QtGui.QAction(mainWindow)
|
||||
self.ViewLivePanel.setCheckable(True)
|
||||
self.ViewLivePanel.setChecked(liveVisible)
|
||||
self.ViewLivePanel.setObjectName(u'ViewLivePanel')
|
||||
MainWindow.actionList.add_action(self.ViewLivePanel, u'View')
|
||||
self.ModeDefaultItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.ViewLivePanel, u'View')
|
||||
self.ModeDefaultItem = QtGui.QAction(mainWindow)
|
||||
self.ModeDefaultItem.setCheckable(True)
|
||||
self.ModeDefaultItem.setObjectName(u'ModeDefaultItem')
|
||||
MainWindow.actionList.add_action(self.ModeDefaultItem, u'View Mode')
|
||||
self.ModeSetupItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.ModeDefaultItem, u'View Mode')
|
||||
self.ModeSetupItem = QtGui.QAction(mainWindow)
|
||||
self.ModeSetupItem.setCheckable(True)
|
||||
self.ModeSetupItem.setObjectName(u'ModeLiveItem')
|
||||
MainWindow.actionList.add_action(self.ModeSetupItem, u'View Mode')
|
||||
self.ModeLiveItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.ModeSetupItem, u'View Mode')
|
||||
self.ModeLiveItem = QtGui.QAction(mainWindow)
|
||||
self.ModeLiveItem.setCheckable(True)
|
||||
self.ModeLiveItem.setObjectName(u'ModeLiveItem')
|
||||
MainWindow.actionList.add_action(self.ModeLiveItem, u'View Mode')
|
||||
self.ModeGroup = QtGui.QActionGroup(MainWindow)
|
||||
mainWindow.actionList.add_action(self.ModeLiveItem, u'View Mode')
|
||||
self.ModeGroup = QtGui.QActionGroup(mainWindow)
|
||||
self.ModeGroup.addAction(self.ModeDefaultItem)
|
||||
self.ModeGroup.addAction(self.ModeSetupItem)
|
||||
self.ModeGroup.addAction(self.ModeLiveItem)
|
||||
self.ModeDefaultItem.setChecked(True)
|
||||
self.ToolsAddToolItem = QtGui.QAction(MainWindow)
|
||||
self.ToolsAddToolItem = QtGui.QAction(mainWindow)
|
||||
self.ToolsAddToolItem.setIcon(build_icon(u':/tools/tools_add.png'))
|
||||
self.ToolsAddToolItem.setObjectName(u'ToolsAddToolItem')
|
||||
MainWindow.actionList.add_action(self.ToolsAddToolItem, u'Tools')
|
||||
self.SettingsPluginListItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.ToolsAddToolItem, u'Tools')
|
||||
self.SettingsPluginListItem = QtGui.QAction(mainWindow)
|
||||
self.SettingsPluginListItem.setIcon(
|
||||
build_icon(u':/system/settings_plugin_list.png'))
|
||||
self.SettingsPluginListItem.setObjectName(u'SettingsPluginListItem')
|
||||
MainWindow.actionList.add_action(self.SettingsPluginListItem,
|
||||
mainWindow.actionList.add_action(self.SettingsPluginListItem,
|
||||
u'Settings')
|
||||
# i18n Language Items
|
||||
self.AutoLanguageItem = QtGui.QAction(MainWindow)
|
||||
self.AutoLanguageItem = QtGui.QAction(mainWindow)
|
||||
self.AutoLanguageItem.setObjectName(u'AutoLanguageItem')
|
||||
self.AutoLanguageItem.setCheckable(True)
|
||||
MainWindow.actionList.add_action(self.AutoLanguageItem, u'Settings')
|
||||
self.LanguageGroup = QtGui.QActionGroup(MainWindow)
|
||||
mainWindow.actionList.add_action(self.AutoLanguageItem, u'Settings')
|
||||
self.LanguageGroup = QtGui.QActionGroup(mainWindow)
|
||||
self.LanguageGroup.setExclusive(True)
|
||||
self.LanguageGroup.setObjectName(u'LanguageGroup')
|
||||
self.AutoLanguageItem.setChecked(LanguageManager.auto_language)
|
||||
@ -262,40 +262,40 @@ class Ui_MainWindow(object):
|
||||
qmList = LanguageManager.get_qm_list()
|
||||
savedLanguage = LanguageManager.get_language()
|
||||
for key in sorted(qmList.keys()):
|
||||
languageItem = QtGui.QAction(MainWindow)
|
||||
languageItem = QtGui.QAction(mainWindow)
|
||||
languageItem.setObjectName(key)
|
||||
languageItem.setCheckable(True)
|
||||
if qmList[key] == savedLanguage:
|
||||
languageItem.setChecked(True)
|
||||
add_actions(self.LanguageGroup, [languageItem])
|
||||
self.SettingsShortcutsItem = QtGui.QAction(MainWindow)
|
||||
self.SettingsShortcutsItem = QtGui.QAction(mainWindow)
|
||||
self.SettingsShortcutsItem.setIcon(
|
||||
build_icon(u':/system/system_configure_shortcuts.png'))
|
||||
self.SettingsShortcutsItem.setObjectName(u'SettingsShortcutsItem')
|
||||
self.SettingsConfigureItem = QtGui.QAction(MainWindow)
|
||||
self.SettingsConfigureItem = QtGui.QAction(mainWindow)
|
||||
self.SettingsConfigureItem.setIcon(
|
||||
build_icon(u':/system/system_settings.png'))
|
||||
self.SettingsConfigureItem.setObjectName(u'SettingsConfigureItem')
|
||||
MainWindow.actionList.add_action(self.SettingsShortcutsItem,
|
||||
mainWindow.actionList.add_action(self.SettingsShortcutsItem,
|
||||
u'Settings')
|
||||
self.HelpDocumentationItem = QtGui.QAction(MainWindow)
|
||||
self.HelpDocumentationItem = QtGui.QAction(mainWindow)
|
||||
self.HelpDocumentationItem.setIcon(
|
||||
build_icon(u':/system/system_help_contents.png'))
|
||||
self.HelpDocumentationItem.setObjectName(u'HelpDocumentationItem')
|
||||
self.HelpDocumentationItem.setEnabled(False)
|
||||
MainWindow.actionList.add_action(self.HelpDocumentationItem, u'Help')
|
||||
self.HelpAboutItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.HelpDocumentationItem, u'Help')
|
||||
self.HelpAboutItem = QtGui.QAction(mainWindow)
|
||||
self.HelpAboutItem.setIcon(
|
||||
build_icon(u':/system/system_about.png'))
|
||||
self.HelpAboutItem.setObjectName(u'HelpAboutItem')
|
||||
MainWindow.actionList.add_action(self.HelpAboutItem, u'Help')
|
||||
self.HelpOnlineHelpItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.HelpAboutItem, u'Help')
|
||||
self.HelpOnlineHelpItem = QtGui.QAction(mainWindow)
|
||||
self.HelpOnlineHelpItem.setObjectName(u'HelpOnlineHelpItem')
|
||||
self.HelpOnlineHelpItem.setEnabled(False)
|
||||
MainWindow.actionList.add_action(self.HelpOnlineHelpItem, u'Help')
|
||||
self.HelpWebSiteItem = QtGui.QAction(MainWindow)
|
||||
mainWindow.actionList.add_action(self.HelpOnlineHelpItem, u'Help')
|
||||
self.HelpWebSiteItem = QtGui.QAction(mainWindow)
|
||||
self.HelpWebSiteItem.setObjectName(u'HelpWebSiteItem')
|
||||
MainWindow.actionList.add_action(self.HelpWebSiteItem, u'Help')
|
||||
mainWindow.actionList.add_action(self.HelpWebSiteItem, u'Help')
|
||||
add_actions(self.FileImportMenu,
|
||||
(self.ImportThemeItem, self.ImportLanguageItem))
|
||||
add_actions(self.FileExportMenu,
|
||||
@ -324,21 +324,21 @@ class Ui_MainWindow(object):
|
||||
self.ViewMenu.menuAction(), self.ToolsMenu.menuAction(),
|
||||
self.SettingsMenu.menuAction(), self.HelpMenu.menuAction()))
|
||||
# Initialise the translation
|
||||
self.retranslateUi(MainWindow)
|
||||
self.retranslateUi(mainWindow)
|
||||
self.MediaToolBox.setCurrentIndex(0)
|
||||
# Connect up some signals and slots
|
||||
QtCore.QObject.connect(self.FileMenu,
|
||||
QtCore.SIGNAL(u'aboutToShow()'), self.updateFileMenu)
|
||||
QtCore.QObject.connect(self.FileExitItem,
|
||||
QtCore.SIGNAL(u'triggered()'), MainWindow.close)
|
||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||
QtCore.SIGNAL(u'triggered()'), mainWindow.close)
|
||||
QtCore.QMetaObject.connectSlotsByName(mainWindow)
|
||||
|
||||
def retranslateUi(self, MainWindow):
|
||||
def retranslateUi(self, mainWindow):
|
||||
"""
|
||||
Set up the translation system
|
||||
"""
|
||||
MainWindow.mainTitle = translate('OpenLP.MainWindow', 'OpenLP 2.0')
|
||||
MainWindow.setWindowTitle(MainWindow.mainTitle)
|
||||
mainWindow.mainTitle = translate('OpenLP.MainWindow', 'OpenLP 2.0')
|
||||
mainWindow.setWindowTitle(mainWindow.mainTitle)
|
||||
self.FileMenu.setTitle(translate('OpenLP.MainWindow', '&File'))
|
||||
self.FileImportMenu.setTitle(translate('OpenLP.MainWindow', '&Import'))
|
||||
self.FileExportMenu.setTitle(translate('OpenLP.MainWindow', '&Export'))
|
||||
@ -450,39 +450,34 @@ class Ui_MainWindow(object):
|
||||
self.HelpAboutItem.setText(translate('OpenLP.MainWindow', '&About'))
|
||||
self.HelpAboutItem.setStatusTip(
|
||||
translate('OpenLP.MainWindow', 'More information about OpenLP'))
|
||||
self.HelpAboutItem.setShortcut(translate('OpenLP.MainWindow',
|
||||
'Ctrl+F1'))
|
||||
self.HelpAboutItem.setShortcut(
|
||||
translate('OpenLP.MainWindow', 'Ctrl+F1'))
|
||||
self.HelpOnlineHelpItem.setText(
|
||||
translate('OpenLP.MainWindow', '&Online Help'))
|
||||
self.HelpWebSiteItem.setText(
|
||||
translate('OpenLP.MainWindow', '&Web Site'))
|
||||
self.AutoLanguageItem.setText(
|
||||
translate('OpenLP.MainWindow', '&Auto Detect'))
|
||||
self.AutoLanguageItem.setStatusTip(
|
||||
translate('OpenLP.MainWindow',
|
||||
'Use the system language, if available.'))
|
||||
self.AutoLanguageItem.setStatusTip(translate('OpenLP.MainWindow',
|
||||
'Use the system language, if available.'))
|
||||
for item in self.LanguageGroup.actions():
|
||||
item.setText(item.objectName())
|
||||
item.setStatusTip(unicode(translate('OpenLP.MainWindow',
|
||||
'Set the interface language to %s')) % item.objectName())
|
||||
self.ToolsAddToolItem.setText(
|
||||
translate('OpenLP.MainWindow', 'Add &Tool...'))
|
||||
self.ToolsAddToolItem.setStatusTip(
|
||||
translate('OpenLP.MainWindow',
|
||||
'Add an application to the list of tools.'))
|
||||
self.ToolsAddToolItem.setStatusTip(translate('OpenLP.MainWindow',
|
||||
'Add an application to the list of tools.'))
|
||||
self.ModeDefaultItem.setText(
|
||||
translate('OpenLP.MainWindow', '&Default'))
|
||||
self.ModeDefaultItem.setStatusTip(
|
||||
translate('OpenLP.MainWindow',
|
||||
'Set the view mode back to the default.'))
|
||||
self.ModeDefaultItem.setStatusTip(translate('OpenLP.MainWindow',
|
||||
'Set the view mode back to the default.'))
|
||||
self.ModeSetupItem.setText(translate('OpenLP.MainWindow', '&Setup'))
|
||||
self.ModeSetupItem.setStatusTip(
|
||||
translate('OpenLP.MainWindow',
|
||||
'Set the view mode to Setup.'))
|
||||
translate('OpenLP.MainWindow', 'Set the view mode to Setup.'))
|
||||
self.ModeLiveItem.setText(translate('OpenLP.MainWindow', '&Live'))
|
||||
self.ModeLiveItem.setStatusTip(
|
||||
translate('OpenLP.MainWindow',
|
||||
'Set the view mode to Live.'))
|
||||
translate('OpenLP.MainWindow', 'Set the view mode to Live.'))
|
||||
|
||||
|
||||
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
||||
|
@ -49,34 +49,6 @@ class ServiceManagerList(QtGui.QTreeWidget):
|
||||
QtGui.QTreeWidget.__init__(self, parent)
|
||||
self.mainwindow = mainwindow
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if isinstance(event, QtGui.QKeyEvent):
|
||||
#here accept the event and do something
|
||||
if event.key() == QtCore.Qt.Key_Enter:
|
||||
self.mainwindow.makeLive()
|
||||
event.accept()
|
||||
elif event.key() == QtCore.Qt.Key_Home:
|
||||
self.mainwindow.onServiceTop()
|
||||
event.accept()
|
||||
elif event.key() == QtCore.Qt.Key_End:
|
||||
self.mainwindow.onServiceEnd()
|
||||
event.accept()
|
||||
elif event.key() == QtCore.Qt.Key_PageUp:
|
||||
self.mainwindow.onServiceUp()
|
||||
event.accept()
|
||||
elif event.key() == QtCore.Qt.Key_PageDown:
|
||||
self.mainwindow.onServiceDown()
|
||||
event.accept()
|
||||
elif event.key() == QtCore.Qt.Key_Up:
|
||||
self.mainwindow.onMoveSelectionUp()
|
||||
event.accept()
|
||||
elif event.key() == QtCore.Qt.Key_Down:
|
||||
self.mainwindow.onMoveSelectionDown()
|
||||
event.accept()
|
||||
event.ignore()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
"""
|
||||
Drag and drop event does not care what data is selected
|
||||
@ -178,50 +150,72 @@ class ServiceManager(QtGui.QWidget):
|
||||
self.layout.addWidget(self.serviceManagerList)
|
||||
# Add the bottom toolbar
|
||||
self.orderToolbar = OpenLPToolbar(self)
|
||||
self.orderToolbar.addToolbarButton(
|
||||
self.serviceManagerList.moveTop = self.orderToolbar.addToolbarButton(
|
||||
translate('OpenLP.ServiceManager', 'Move to &top'),
|
||||
u':/services/service_top.png',
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Move item to the top of the service.'),
|
||||
self.onServiceTop)
|
||||
self.orderToolbar.addToolbarButton(
|
||||
self.onServiceTop, shortcut=QtCore.Qt.Key_Home)
|
||||
self.serviceManagerList.moveUp = self.orderToolbar.addToolbarButton(
|
||||
translate('OpenLP.ServiceManager', 'Move &up'),
|
||||
u':/services/service_up.png',
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Move item up one position in the service.'),
|
||||
self.onServiceUp)
|
||||
self.orderToolbar.addToolbarButton(
|
||||
self.onServiceUp, shortcut=QtCore.Qt.Key_PageUp)
|
||||
self.serviceManagerList.moveDown = self.orderToolbar.addToolbarButton(
|
||||
translate('OpenLP.ServiceManager', 'Move &down'),
|
||||
u':/services/service_down.png',
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Move item down one position in the service.'),
|
||||
self.onServiceDown)
|
||||
self.orderToolbar.addToolbarButton(
|
||||
self.onServiceDown, shortcut=QtCore.Qt.Key_PageDown)
|
||||
self.serviceManagerList.moveBottom = self.orderToolbar.addToolbarButton(
|
||||
translate('OpenLP.ServiceManager', 'Move to &bottom'),
|
||||
u':/services/service_bottom.png',
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Move item to the end of the service.'),
|
||||
self.onServiceEnd)
|
||||
self.onServiceEnd, shortcut=QtCore.Qt.Key_End)
|
||||
self.serviceManagerList.down = self.orderToolbar.addToolbarButton(
|
||||
translate('OpenLP.ServiceManager', 'Move &down'),
|
||||
None,
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Moves the selection up the window.'),
|
||||
self.onMoveSelectionDown, shortcut=QtCore.Qt.Key_Up)
|
||||
self.serviceManagerList.down.setVisible(False)
|
||||
self.serviceManagerList.up = self.orderToolbar.addToolbarButton(
|
||||
translate('OpenLP.ServiceManager', 'Move up'),
|
||||
None,
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Moves the selection up the window.'),
|
||||
self.onMoveSelectionUp, shortcut=QtCore.Qt.Key_Up)
|
||||
self.serviceManagerList.up.setVisible(False)
|
||||
self.orderToolbar.addSeparator()
|
||||
self.orderToolbar.addToolbarButton(
|
||||
self.serviceManagerList.delete = self.orderToolbar.addToolbarButton(
|
||||
translate('OpenLP.ServiceManager', '&Delete From Service'),
|
||||
u':/general/general_delete.png',
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Delete the selected item from the service.'),
|
||||
self.onDeleteFromService)
|
||||
self.orderToolbar.addSeparator()
|
||||
self.orderToolbar.addToolbarButton(
|
||||
self.serviceManagerList.expand = self.orderToolbar.addToolbarButton(
|
||||
translate('OpenLP.ServiceManager', '&Expand all'),
|
||||
u':/services/service_expand_all.png',
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Expand all the service items.'),
|
||||
self.onExpandAll)
|
||||
self.orderToolbar.addToolbarButton(
|
||||
self.serviceManagerList.collapse = self.orderToolbar.addToolbarButton(
|
||||
translate('OpenLP.ServiceManager', '&Collapse all'),
|
||||
u':/services/service_collapse_all.png',
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Collapse all the service items.'),
|
||||
self.onCollapseAll)
|
||||
self.orderToolbar.addSeparator()
|
||||
self.serviceManagerList.makeLive = self.orderToolbar.addToolbarButton(
|
||||
translate('OpenLP.ServiceManager', 'Go Live'),
|
||||
u':/general/general_live.png',
|
||||
translate('OpenLP.ServiceManager',
|
||||
'Send the selected item to Live.'),
|
||||
self.makeLive, shortcut=QtCore.Qt.Key_Enter,
|
||||
alternate=QtCore.Qt.Key_Return)
|
||||
self.orderToolbar.setObjectName(u'orderToolbar')
|
||||
self.layout.addWidget(self.orderToolbar)
|
||||
# Connect up our signals and slots
|
||||
@ -245,6 +239,9 @@ class ServiceManager(QtGui.QWidget):
|
||||
QtCore.SIGNAL(u'servicemanager_list_request'), self.listRequest)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'config_updated'), self.configUpdated)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'config_screen_changed'),
|
||||
self.regenerateServiceItems)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'theme_update_global'), self.themeChange)
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
@ -289,7 +286,27 @@ class ServiceManager(QtGui.QWidget):
|
||||
self.themeMenu = QtGui.QMenu(
|
||||
translate('OpenLP.ServiceManager', '&Change Item Theme'))
|
||||
self.menu.addMenu(self.themeMenu)
|
||||
self.configUpdated(True)
|
||||
self.setServiceHotkeys()
|
||||
self.serviceManagerList.addActions(
|
||||
[self.serviceManagerList.moveDown,
|
||||
self.serviceManagerList.moveUp,
|
||||
self.serviceManagerList.makeLive,
|
||||
self.serviceManagerList.moveTop,
|
||||
self.serviceManagerList.moveBottom,
|
||||
self.serviceManagerList.up,
|
||||
self.serviceManagerList.down
|
||||
])
|
||||
self.configUpdated()
|
||||
|
||||
def setServiceHotkeys(self):
|
||||
actionList = self.mainwindow.actionList
|
||||
actionList.add_action(self.serviceManagerList.moveDown, u'Service')
|
||||
actionList.add_action(self.serviceManagerList.moveUp, u'Service')
|
||||
actionList.add_action(self.serviceManagerList.moveTop, u'Service')
|
||||
actionList.add_action(self.serviceManagerList.moveBottom, u'Service')
|
||||
actionList.add_action(self.serviceManagerList.makeLive, u'Service')
|
||||
actionList.add_action(self.serviceManagerList.up, u'Service')
|
||||
actionList.add_action(self.serviceManagerList.down, u'Service')
|
||||
|
||||
def setModified(self, modified=True):
|
||||
"""
|
||||
@ -328,15 +345,13 @@ class ServiceManager(QtGui.QWidget):
|
||||
"""
|
||||
return split_filename(self._fileName)[1]
|
||||
|
||||
def configUpdated(self, firstTime=False):
|
||||
def configUpdated(self):
|
||||
"""
|
||||
Triggered when Config dialog is updated.
|
||||
"""
|
||||
self.expandTabs = QtCore.QSettings().value(
|
||||
u'advanced/expand service item',
|
||||
QtCore.QVariant(u'False')).toBool()
|
||||
if not firstTime:
|
||||
self.regenerateServiceItems()
|
||||
|
||||
def supportedSuffixes(self, suffix):
|
||||
self.suffixes.append(suffix)
|
||||
@ -793,17 +808,17 @@ class ServiceManager(QtGui.QWidget):
|
||||
self.repaintServiceList(0, 0)
|
||||
self.setModified(True)
|
||||
|
||||
def repaintServiceList(self, serviceItem, serviceItemCount):
|
||||
def repaintServiceList(self, serviceItem, serviceItemChild):
|
||||
"""
|
||||
Clear the existing service list and prepaint all the items. This is
|
||||
used when moving items as the move takes place in a supporting list,
|
||||
and when regenerating all the items due to theme changes.
|
||||
|
||||
``serviceItem``
|
||||
The item which changed.
|
||||
The item which changed. (int)
|
||||
|
||||
``serviceItemCount``
|
||||
The number of items in the service.
|
||||
``serviceItemChild``
|
||||
The child of the ``serviceItem``, which will be selected. (int)
|
||||
"""
|
||||
# Correct order of items in array
|
||||
count = 1
|
||||
@ -836,17 +851,17 @@ class ServiceManager(QtGui.QWidget):
|
||||
treewidgetitem.setToolTip(0, serviceitem.notes)
|
||||
treewidgetitem.setData(0, QtCore.Qt.UserRole,
|
||||
QtCore.QVariant(item[u'order']))
|
||||
# Add the children to their parent treewidgetitem.
|
||||
for count, frame in enumerate(serviceitem.get_frames()):
|
||||
treewidgetitem1 = QtGui.QTreeWidgetItem(treewidgetitem)
|
||||
child = QtGui.QTreeWidgetItem(treewidgetitem)
|
||||
text = frame[u'title'].replace(u'\n', u' ')
|
||||
treewidgetitem1.setText(0, text[:40])
|
||||
treewidgetitem1.setData(0, QtCore.Qt.UserRole,
|
||||
QtCore.QVariant(count))
|
||||
if serviceItem == itemcount and serviceItemCount == count:
|
||||
#preserve expanding status as setCurrentItem sets it to True
|
||||
temp = item[u'expanded']
|
||||
self.serviceManagerList.setCurrentItem(treewidgetitem1)
|
||||
item[u'expanded'] = temp
|
||||
child.setText(0, text[:40])
|
||||
child.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(count))
|
||||
if serviceItem == itemcount:
|
||||
if item[u'expanded'] and serviceItemChild == count:
|
||||
self.serviceManagerList.setCurrentItem(child)
|
||||
elif serviceItemChild == -1:
|
||||
self.serviceManagerList.setCurrentItem(treewidgetitem)
|
||||
treewidgetitem.setExpanded(item[u'expanded'])
|
||||
|
||||
def validateItem(self, serviceItem):
|
||||
@ -957,7 +972,7 @@ class ServiceManager(QtGui.QWidget):
|
||||
if replace:
|
||||
item.merge(self.serviceItems[sitem][u'service_item'])
|
||||
self.serviceItems[sitem][u'service_item'] = item
|
||||
self.repaintServiceList(sitem + 1, 0)
|
||||
self.repaintServiceList(sitem, 0)
|
||||
self.mainwindow.liveController.replaceServiceManagerItem(item)
|
||||
else:
|
||||
# nothing selected for dnd
|
||||
@ -1024,7 +1039,7 @@ class ServiceManager(QtGui.QWidget):
|
||||
ItemCapabilities.AllowsPreview):
|
||||
self.mainwindow.previewController.addServiceManagerItem(
|
||||
self.serviceItems[item][u'service_item'], 0)
|
||||
self.mainwindow.liveController.PreviewListWidget.setFocus()
|
||||
self.mainwindow.liveController.previewListWidget.setFocus()
|
||||
else:
|
||||
criticalErrorMessageBox(
|
||||
translate('OpenLP.ServiceManager', 'Missing Display Handler'),
|
||||
@ -1045,11 +1060,16 @@ class ServiceManager(QtGui.QWidget):
|
||||
|
||||
def findServiceItem(self):
|
||||
"""
|
||||
Finds a ServiceItem in the list
|
||||
Finds a ServiceItem in the list and returns the position of the
|
||||
serviceitem and its selected child item. For example, if the third child
|
||||
item (in the Slidecontroller known as slide) in the second service item
|
||||
is selected this will return::
|
||||
|
||||
(1, 2)
|
||||
"""
|
||||
items = self.serviceManagerList.selectedItems()
|
||||
pos = 0
|
||||
count = 0
|
||||
count = -1
|
||||
for item in items:
|
||||
parentitem = item.parent()
|
||||
if parentitem is None:
|
||||
@ -1081,7 +1101,7 @@ class ServiceManager(QtGui.QWidget):
|
||||
"""
|
||||
link = event.mimeData()
|
||||
if link.hasText():
|
||||
plugin = event.mimeData().text()
|
||||
plugin = unicode(event.mimeData().text())
|
||||
item = self.serviceManagerList.itemAt(event.pos())
|
||||
# ServiceManager started the drag and drop
|
||||
if plugin == u'ServiceManager':
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -47,6 +47,8 @@ from openlp.core.lib import Receiver, translate
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
IMAGES_FILTER = None
|
||||
UNO_CONNECTION_TYPE = u'pipe'
|
||||
#UNO_CONNECTION_TYPE = u'socket'
|
||||
|
||||
class VersionThread(QtCore.QThread):
|
||||
"""
|
||||
@ -121,18 +123,6 @@ class AppLocation(object):
|
||||
return _get_frozen_path(
|
||||
os.path.abspath(os.path.split(sys.argv[0])[0]),
|
||||
os.path.split(openlp.__file__)[0])
|
||||
elif dir_type == AppLocation.ConfigDir:
|
||||
return _get_os_dir_path(u'openlp',
|
||||
os.path.join(os.getenv(u'HOME'), u'Library',
|
||||
u'Application Support', u'openlp'),
|
||||
os.path.join(BaseDirectory.xdg_config_home, u'openlp'),
|
||||
os.path.join(os.getenv(u'HOME'), u'.openlp'))
|
||||
elif dir_type == AppLocation.DataDir:
|
||||
return _get_os_dir_path(os.path.join(u'openlp', u'data'),
|
||||
os.path.join(os.getenv(u'HOME'), u'Library',
|
||||
u'Application Support', u'openlp', u'Data'),
|
||||
os.path.join(BaseDirectory.xdg_data_home, u'openlp'),
|
||||
os.path.join(os.getenv(u'HOME'), u'.openlp', u'data'))
|
||||
elif dir_type == AppLocation.PluginsDir:
|
||||
app_path = os.path.abspath(os.path.split(sys.argv[0])[0])
|
||||
return _get_frozen_path(os.path.join(app_path, u'plugins'),
|
||||
@ -141,17 +131,16 @@ class AppLocation(object):
|
||||
return _get_frozen_path(
|
||||
os.path.abspath(os.path.split(sys.argv[0])[0]),
|
||||
os.path.split(openlp.__file__)[0])
|
||||
elif dir_type == AppLocation.CacheDir:
|
||||
return _get_os_dir_path(u'openlp',
|
||||
os.path.join(os.getenv(u'HOME'), u'Library',
|
||||
u'Application Support', u'openlp'),
|
||||
os.path.join(BaseDirectory.xdg_cache_home, u'openlp'),
|
||||
os.path.join(os.getenv(u'HOME'), u'.openlp'))
|
||||
if dir_type == AppLocation.LanguageDir:
|
||||
elif dir_type == AppLocation.LanguageDir:
|
||||
app_path = _get_frozen_path(
|
||||
os.path.abspath(os.path.split(sys.argv[0])[0]),
|
||||
os.path.split(openlp.__file__)[0])
|
||||
return os.path.join(app_path, u'i18n')
|
||||
else:
|
||||
return _get_os_dir_path(u'openlp',
|
||||
os.path.join(os.getenv(u'HOME'), u'Library',
|
||||
u'Application Support', u'openlp'),
|
||||
None, os.path.join(os.getenv(u'HOME'), u'.openlp'), dir_type)
|
||||
|
||||
@staticmethod
|
||||
def get_data_path():
|
||||
@ -175,17 +164,24 @@ class AppLocation(object):
|
||||
return path
|
||||
|
||||
def _get_os_dir_path(win_option, darwin_option, base_dir_option,
|
||||
non_base_dir_option):
|
||||
non_base_dir_option, dir_type=1):
|
||||
"""
|
||||
Return a path based on which OS and environment we are running in.
|
||||
"""
|
||||
if sys.platform == u'win32':
|
||||
return os.path.join(os.getenv(u'APPDATA'), win_option)
|
||||
elif sys.platform == u'darwin':
|
||||
if dir_type == AppLocation.DataDir:
|
||||
return os.path.join(darwin_option, u'Data')
|
||||
return darwin_option
|
||||
else:
|
||||
if XDG_BASE_AVAILABLE:
|
||||
return base_dir_option
|
||||
if dir_type == AppLocation.ConfigDir:
|
||||
return os.path.join(BaseDirectory.xdg_config_home, u'openlp')
|
||||
elif dir_type == AppLocation.DataDir:
|
||||
return os.path.join(BaseDirectory.xdg_data_home, u'openlp')
|
||||
elif dir_type == AppLocation.CacheDir:
|
||||
return os.path.join(BaseDirectory.xdg_cache_home, u'openlp')
|
||||
else:
|
||||
return non_base_dir_option
|
||||
|
||||
@ -375,9 +371,37 @@ def string_is_unicode(test_string):
|
||||
log.exception("Error encoding string to unicode")
|
||||
return return_string
|
||||
|
||||
def get_uno_command():
|
||||
"""
|
||||
Returns the UNO command to launch an openoffice.org instance.
|
||||
"""
|
||||
if UNO_CONNECTION_TYPE == u'pipe':
|
||||
return u'openoffice.org -nologo -norestore -minimized -invisible ' \
|
||||
+ u'-nofirststartwizard -accept=pipe,name=openlp_pipe;urp;'
|
||||
else:
|
||||
return u'openoffice.org -nologo -norestore -minimized ' \
|
||||
+ u'-invisible -nofirststartwizard ' \
|
||||
+ u'-accept=socket,host=localhost,port=2002;urp;'
|
||||
|
||||
def get_uno_instance(resolver):
|
||||
"""
|
||||
Returns a running openoffice.org instance.
|
||||
|
||||
``resolver``
|
||||
The UNO resolver to use to find a running instance.
|
||||
"""
|
||||
log.debug(u'get UNO Desktop Openoffice - resolve')
|
||||
if UNO_CONNECTION_TYPE == u'pipe':
|
||||
return resolver.resolve(u'uno:pipe,name=openlp_pipe;' \
|
||||
+ u'urp;StarOffice.ComponentContext')
|
||||
else:
|
||||
return resolver.resolve(u'uno:socket,host=localhost,port=2002;' \
|
||||
+ u'urp;StarOffice.ComponentContext')
|
||||
|
||||
from languagemanager import LanguageManager
|
||||
from actions import ActionList
|
||||
|
||||
__all__ = [u'AppLocation', u'check_latest_version', u'add_actions',
|
||||
u'get_filesystem_encoding', u'LanguageManager', u'ActionList',
|
||||
u'get_web_page', u'file_is_unicode', u'string_is_unicode']
|
||||
u'get_web_page', u'file_is_unicode', u'string_is_unicode',
|
||||
u'get_uno_command', u'get_uno_instance', u'delete_file']
|
||||
|
@ -27,7 +27,6 @@
|
||||
The :mod:`~openlp.core.utils.actions` module provides action list classes used
|
||||
by the shortcuts system.
|
||||
"""
|
||||
|
||||
class ActionCategory(object):
|
||||
"""
|
||||
The :class:`~openlp.core.utils.ActionCategory` class encapsulates a
|
||||
@ -181,4 +180,4 @@ class ActionList(object):
|
||||
if weight is None:
|
||||
self.categories[category].actions.append(action)
|
||||
else:
|
||||
self.categories[category].actions.add(action, weight)
|
||||
self.categories[category].actions.add(action, weight)
|
||||
|
@ -109,7 +109,7 @@ def parse_reference(reference):
|
||||
regular expression looks like this:
|
||||
|
||||
1. ``^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*``
|
||||
The ``book`` group starts with the first non-whitespace character. There
|
||||
The ``book`` group starts with the first non-whitespace character. There
|
||||
are optional leading digits followed by non-digits. The group ends
|
||||
before the whitspace in front of the next digit.
|
||||
2. ``(?P<ranges>(?:`` + range_string + ``(?:%(sep_l)s|(?=\s*$)))+)\s*$``
|
||||
@ -177,7 +177,7 @@ def parse_reference(reference):
|
||||
to_verse = -1
|
||||
if to_chapter > from_chapter:
|
||||
ref_list.append((book, from_chapter, from_verse, -1))
|
||||
for i in range(from_chapter + 1, to_chapter - 1):
|
||||
for i in range(from_chapter + 1, to_chapter):
|
||||
ref_list.append((book, i, 1, -1))
|
||||
ref_list.append((book, to_chapter, 1, to_verse))
|
||||
elif to_verse >= from_verse or to_verse == -1:
|
||||
|
@ -507,6 +507,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
"""
|
||||
log.debug(u'Advanced Search Button pressed')
|
||||
self.advancedSearchButton.setEnabled(False)
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
bible = unicode(self.advancedVersionComboBox.currentText())
|
||||
second_bible = unicode(self.advancedSecondComboBox.currentText())
|
||||
book = unicode(self.advancedBookComboBox.currentText())
|
||||
@ -519,6 +520,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
verse_range = chapter_from + verse_separator + verse_from + \
|
||||
range_separator + chapter_to + verse_separator + verse_to
|
||||
versetext = u'%s %s' % (book, verse_range)
|
||||
Receiver.send_message(u'cursor_busy')
|
||||
self.search_results = self.parent.manager.get_verses(bible, versetext)
|
||||
if second_bible:
|
||||
self.second_search_results = self.parent.manager.get_verses(
|
||||
@ -541,7 +543,9 @@ class BibleMediaItem(MediaManagerItem):
|
||||
self.displayResults(bible, second_bible)
|
||||
else:
|
||||
self.displayResults(bible, second_bible)
|
||||
Receiver.send_message(u'cursor_normal')
|
||||
self.advancedSearchButton.setEnabled(True)
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
|
||||
def onQuickSearchButton(self):
|
||||
"""
|
||||
@ -550,6 +554,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
"""
|
||||
log.debug(u'Quick Search Button pressed')
|
||||
self.quickSearchButton.setEnabled(False)
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
bible = unicode(self.quickVersionComboBox.currentText())
|
||||
second_bible = unicode(self.quickSecondComboBox.currentText())
|
||||
text = unicode(self.quickSearchEdit.text())
|
||||
@ -591,6 +596,7 @@ class BibleMediaItem(MediaManagerItem):
|
||||
self.displayResults(bible, second_bible)
|
||||
self.quickSearchButton.setEnabled(True)
|
||||
Receiver.send_message(u'cursor_normal')
|
||||
Receiver.send_message(u'openlp_process_events')
|
||||
|
||||
def displayResults(self, bible, second_bible=u''):
|
||||
"""
|
||||
|
Binary file not shown.
@ -51,7 +51,7 @@ else:
|
||||
|
||||
from PyQt4 import QtCore
|
||||
|
||||
from openlp.core.utils import delete_file
|
||||
from openlp.core.utils import delete_file, get_uno_command, get_uno_instance
|
||||
from presentationcontroller import PresentationController, PresentationDocument
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -75,7 +75,6 @@ class ImpressController(PresentationController):
|
||||
self.process = None
|
||||
self.desktop = None
|
||||
self.manager = None
|
||||
self.uno_connection_type = u'pipe' #u'socket'
|
||||
|
||||
def check_available(self):
|
||||
"""
|
||||
@ -100,14 +99,7 @@ class ImpressController(PresentationController):
|
||||
self.manager._FlagAsMethod(u'Bridge_GetValueObject')
|
||||
else:
|
||||
# -headless
|
||||
if self.uno_connection_type == u'pipe':
|
||||
cmd = u'openoffice.org -nologo -norestore -minimized ' \
|
||||
+ u'-invisible -nofirststartwizard ' \
|
||||
+ u'-accept=pipe,name=openlp_pipe;urp;'
|
||||
else:
|
||||
cmd = u'openoffice.org -nologo -norestore -minimized ' \
|
||||
+ u'-invisible -nofirststartwizard ' \
|
||||
+ u'-accept=socket,host=localhost,port=2002;urp;'
|
||||
cmd = get_uno_command()
|
||||
self.process = QtCore.QProcess()
|
||||
self.process.startDetached(cmd)
|
||||
self.process.waitForStarted()
|
||||
@ -118,7 +110,7 @@ class ImpressController(PresentationController):
|
||||
which will be used to manage impress
|
||||
"""
|
||||
log.debug(u'get UNO Desktop Openoffice')
|
||||
ctx = None
|
||||
uno_instance = None
|
||||
loop = 0
|
||||
log.debug(u'get UNO Desktop Openoffice - getComponentContext')
|
||||
context = uno.getComponentContext()
|
||||
@ -126,27 +118,19 @@ class ImpressController(PresentationController):
|
||||
u'UnoUrlResolver')
|
||||
resolver = context.ServiceManager.createInstanceWithContext(
|
||||
u'com.sun.star.bridge.UnoUrlResolver', context)
|
||||
while ctx is None and loop < 3:
|
||||
while uno_instance is None and loop < 3:
|
||||
try:
|
||||
log.debug(u'get UNO Desktop Openoffice - resolve')
|
||||
if self.uno_connection_type == u'pipe':
|
||||
ctx = resolver.resolve(u'uno:' \
|
||||
+ u'pipe,name=openlp_pipe;' \
|
||||
+ u'urp;StarOffice.ComponentContext')
|
||||
else:
|
||||
ctx = resolver.resolve(u'uno:' \
|
||||
+ u'socket,host=localhost,port=2002;' \
|
||||
+ u'urp;StarOffice.ComponentContext')
|
||||
uno_instance = get_uno_instance(resolver)
|
||||
except:
|
||||
log.exception(u'Unable to find running instance ')
|
||||
self.start_process()
|
||||
loop += 1
|
||||
try:
|
||||
self.manager = ctx.ServiceManager
|
||||
self.manager = uno_instance.ServiceManager
|
||||
log.debug(u'get UNO Desktop Openoffice - createInstanceWithContext'
|
||||
u' - Desktop')
|
||||
desktop = self.manager.createInstanceWithContext(
|
||||
"com.sun.star.frame.Desktop", ctx )
|
||||
"com.sun.star.frame.Desktop", uno_instance)
|
||||
return desktop
|
||||
except:
|
||||
log.exception(u'Failed to get UNO desktop')
|
||||
|
@ -268,12 +268,22 @@ class PresentationMediaItem(MediaManagerItem):
|
||||
doc.load_presentation()
|
||||
i = 1
|
||||
img = doc.get_thumbnail_path(i, True)
|
||||
while img:
|
||||
service_item.add_from_command(path, name, img)
|
||||
i = i + 1
|
||||
img = doc.get_thumbnail_path(i, True)
|
||||
doc.close_presentation()
|
||||
return True
|
||||
if img:
|
||||
while img:
|
||||
service_item.add_from_command(path, name, img)
|
||||
i = i + 1
|
||||
img = doc.get_thumbnail_path(i, True)
|
||||
doc.close_presentation()
|
||||
return True
|
||||
else:
|
||||
# File is no longer present
|
||||
criticalErrorMessageBox(
|
||||
translate('PresentationPlugin.MediaItem',
|
||||
'Missing Presentation'),
|
||||
unicode(translate('PresentationPlugin.MediaItem',
|
||||
'The Presentation %s is incomplete,'
|
||||
' please reload.')) % filename)
|
||||
return False
|
||||
else:
|
||||
# File is no longer present
|
||||
criticalErrorMessageBox(
|
||||
|
@ -553,7 +553,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
||||
return False
|
||||
if self.verseOrderEdit.text():
|
||||
order = []
|
||||
order_names = self.verseOrderEdit.text().split()
|
||||
order_names = unicode(self.verseOrderEdit.text()).split()
|
||||
for item in order_names:
|
||||
if len(item) == 1:
|
||||
order.append(item.lower() + u'1')
|
||||
|
@ -654,7 +654,7 @@ class SongImportForm(OpenLPWizard):
|
||||
'Select EasiSlides songfile'),
|
||||
self.easiSlidesFilenameEdit
|
||||
)
|
||||
|
||||
|
||||
def onEWBrowseButtonClicked(self):
|
||||
"""
|
||||
Get EasyWorship song database files
|
||||
@ -784,7 +784,6 @@ class SongImportForm(OpenLPWizard):
|
||||
filenames=self.getListOfFiles(self.songBeamerFileListWidget)
|
||||
)
|
||||
if importer.do_import():
|
||||
# reload songs
|
||||
self.progressLabel.setText(
|
||||
translate('SongsPlugin.SongImportForm', 'Finished import.'))
|
||||
else:
|
||||
|
@ -50,6 +50,14 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
||||
self.authorform = AuthorsForm(self)
|
||||
self.topicform = TopicsForm(self)
|
||||
self.bookform = SongBookForm(self)
|
||||
# Disable all edit and delete buttons, as there is no row selected.
|
||||
self.authorsDeleteButton.setEnabled(False)
|
||||
self.authorsEditButton.setEnabled(False)
|
||||
self.topicsDeleteButton.setEnabled(False)
|
||||
self.topicsEditButton.setEnabled(False)
|
||||
self.booksDeleteButton.setEnabled(False)
|
||||
self.booksEditButton.setEnabled(False)
|
||||
# Signals
|
||||
QtCore.QObject.connect(self.authorsAddButton,
|
||||
QtCore.SIGNAL(u'pressed()'), self.onAuthorAddButtonClick)
|
||||
QtCore.QObject.connect(self.topicsAddButton,
|
||||
@ -68,6 +76,15 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
||||
QtCore.SIGNAL(u'pressed()'), self.onTopicDeleteButtonClick)
|
||||
QtCore.QObject.connect(self.booksDeleteButton,
|
||||
QtCore.SIGNAL(u'pressed()'), self.onBookDeleteButtonClick)
|
||||
QtCore.QObject.connect(self.authorsListWidget,
|
||||
QtCore.SIGNAL(u'currentRowChanged(int)'),
|
||||
self.onAuthorsListRowChanged)
|
||||
QtCore.QObject.connect(self.topicsListWidget,
|
||||
QtCore.SIGNAL(u'currentRowChanged(int)'),
|
||||
self.onTopicsListRowChanged)
|
||||
QtCore.QObject.connect(self.booksListWidget,
|
||||
QtCore.SIGNAL(u'currentRowChanged(int)'),
|
||||
self.onBooksListRowChanged)
|
||||
|
||||
def exec_(self):
|
||||
self.typeListWidget.setCurrentRow(0)
|
||||
@ -115,12 +132,6 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
||||
u' '.join([author.first_name, author.last_name]))
|
||||
author_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(author.id))
|
||||
self.authorsListWidget.addItem(author_name)
|
||||
if self.authorsListWidget.count() == 0:
|
||||
self.authorsDeleteButton.setEnabled(False)
|
||||
self.authorsEditButton.setEnabled(False)
|
||||
else:
|
||||
self.authorsDeleteButton.setEnabled(True)
|
||||
self.authorsEditButton.setEnabled(True)
|
||||
|
||||
def resetTopics(self):
|
||||
"""
|
||||
@ -132,12 +143,6 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
||||
topic_name = QtGui.QListWidgetItem(topic.name)
|
||||
topic_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(topic.id))
|
||||
self.topicsListWidget.addItem(topic_name)
|
||||
if self.topicsListWidget.count() == 0:
|
||||
self.topicsDeleteButton.setEnabled(False)
|
||||
self.topicsEditButton.setEnabled(False)
|
||||
else:
|
||||
self.topicsDeleteButton.setEnabled(True)
|
||||
self.topicsEditButton.setEnabled(True)
|
||||
|
||||
def resetBooks(self):
|
||||
"""
|
||||
@ -150,31 +155,27 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
||||
book.publisher))
|
||||
book_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(book.id))
|
||||
self.booksListWidget.addItem(book_name)
|
||||
if self.booksListWidget.count() == 0:
|
||||
self.booksDeleteButton.setEnabled(False)
|
||||
self.booksEditButton.setEnabled(False)
|
||||
else:
|
||||
self.booksDeleteButton.setEnabled(True)
|
||||
self.booksEditButton.setEnabled(True)
|
||||
|
||||
def checkAuthor(self, new_author, edit=False):
|
||||
"""
|
||||
Returns False if the given Author is already in the list otherwise
|
||||
True.
|
||||
Returns *False* if the given Author already exists, otherwise *True*.
|
||||
|
||||
``edit``
|
||||
If we edit an item, this should be *True*.
|
||||
"""
|
||||
authors = self.manager.get_all_objects(Author,
|
||||
and_(Author.first_name == new_author.first_name,
|
||||
Author.last_name == new_author.last_name,
|
||||
Author.display_name == new_author.display_name))
|
||||
# Check if this author already exists.
|
||||
if len(authors) > 0:
|
||||
# If we edit an existing Author, we need to make sure that we do
|
||||
# not return False when nothing has changed (because this would
|
||||
# cause an error message later on).
|
||||
# not return False when nothing has changed.
|
||||
if edit:
|
||||
if authors[0].id == new_author.id:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
for author in authors:
|
||||
if author.id != new_author.id:
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
@ -182,19 +183,21 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
||||
|
||||
def checkTopic(self, new_topic, edit=False):
|
||||
"""
|
||||
Returns False if the given Topic is already in the list otherwise True.
|
||||
Returns *False* if the given Topic already exists, otherwise *True*.
|
||||
|
||||
``edit``
|
||||
If we edit an item, this should be *True*.
|
||||
"""
|
||||
topics = self.manager.get_all_objects(Topic,
|
||||
Topic.name == new_topic.name)
|
||||
if len(topics) > 0:
|
||||
# If we edit an existing Topic, we need to make sure that we do
|
||||
# not return False when nothing has changed (because this would
|
||||
# cause an error message later on).
|
||||
# not return False when nothing has changed.
|
||||
if edit:
|
||||
if topics[0].id == new_topic.id:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
for topic in topics:
|
||||
if topic.id != new_topic.id:
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
@ -202,20 +205,22 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
||||
|
||||
def checkBook(self, new_book, edit=False):
|
||||
"""
|
||||
Returns False if the given Book is already in the list otherwise True.
|
||||
Returns *False* if the given Topic already exists, otherwise *True*.
|
||||
|
||||
``edit``
|
||||
If we edit an item, this should be *True*.
|
||||
"""
|
||||
books = self.manager.get_all_objects(Book,
|
||||
and_(Book.name == new_book.name,
|
||||
Book.publisher == new_book.publisher))
|
||||
if len(books) > 0:
|
||||
# If we edit an existing Book, we need to make sure that we do
|
||||
# not return False when nothing has changed (because this would
|
||||
# cause an error message later on).
|
||||
# not return False when nothing has changed.
|
||||
if edit:
|
||||
if books[0].id == new_book.id:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
for book in books:
|
||||
if book.id != new_book.id:
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
@ -390,12 +395,14 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
||||
Merges two authors into one author.
|
||||
|
||||
``old_author``
|
||||
The author which will be deleted afterwards.
|
||||
The object, which was edited, that will be deleted
|
||||
"""
|
||||
# Find the duplicate.
|
||||
existing_author = self.manager.get_object_filtered(Author,
|
||||
and_(Author.first_name == old_author.first_name,
|
||||
Author.last_name == old_author.last_name,
|
||||
Author.display_name == old_author.display_name))
|
||||
# Find the songs, which have the old_author as author.
|
||||
songs = self.manager.get_all_objects(Song,
|
||||
Song.authors.contains(old_author))
|
||||
for song in songs:
|
||||
@ -412,10 +419,12 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
||||
Merges two topics into one topic.
|
||||
|
||||
``old_topic``
|
||||
The topic which will be deleted afterwards.
|
||||
The object, which was edited, that will be deleted
|
||||
"""
|
||||
# Find the duplicate.
|
||||
existing_topic = self.manager.get_object_filtered(Topic,
|
||||
Topic.name == old_topic.name)
|
||||
# Find the songs, which have the old_topic as topic.
|
||||
songs = self.manager.get_all_objects(Song,
|
||||
Song.topics.contains(old_topic))
|
||||
for song in songs:
|
||||
@ -432,11 +441,13 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
||||
Merges two books into one book.
|
||||
|
||||
``old_book``
|
||||
The book which will be deleted afterwards.
|
||||
The object, which was edited, that will be deleted
|
||||
"""
|
||||
# Find the duplicate.
|
||||
existing_book = self.manager.get_object_filtered(Book,
|
||||
and_(Book.name == old_book.name,
|
||||
Book.publisher == old_book.publisher))
|
||||
# Find the songs, which have the old_book as book.
|
||||
songs = self.manager.get_all_objects(Song,
|
||||
Song.song_book_id == old_book.id)
|
||||
for song in songs:
|
||||
@ -482,3 +493,45 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
|
||||
'This book cannot be deleted, it is currently '
|
||||
'assigned to at least one song.'),
|
||||
translate('SongsPlugin.SongMaintenanceForm', 'No book selected!'))
|
||||
|
||||
def onAuthorsListRowChanged(self, row):
|
||||
"""
|
||||
Called when the *authorsListWidget* current's row has changed.
|
||||
|
||||
``row``
|
||||
The current row. If there is no current row, the value is -1
|
||||
"""
|
||||
if row == -1:
|
||||
self.authorsDeleteButton.setEnabled(False)
|
||||
self.authorsEditButton.setEnabled(False)
|
||||
else:
|
||||
self.authorsDeleteButton.setEnabled(True)
|
||||
self.authorsEditButton.setEnabled(True)
|
||||
|
||||
def onTopicsListRowChanged(self, row):
|
||||
"""
|
||||
Called when the *booksListWidget* current's row has changed.
|
||||
|
||||
``row``
|
||||
The current row. If there is no current row, the value is -1.
|
||||
"""
|
||||
if row == -1:
|
||||
self.topicsDeleteButton.setEnabled(False)
|
||||
self.topicsEditButton.setEnabled(False)
|
||||
else:
|
||||
self.topicsDeleteButton.setEnabled(True)
|
||||
self.topicsEditButton.setEnabled(True)
|
||||
|
||||
def onBooksListRowChanged(self, row):
|
||||
"""
|
||||
Called when the *booksListWidget* current's row has changed.
|
||||
|
||||
``row``
|
||||
The current row. If there is no current row, the value is -1.
|
||||
"""
|
||||
if row == -1:
|
||||
self.booksDeleteButton.setEnabled(False)
|
||||
self.booksEditButton.setEnabled(False)
|
||||
else:
|
||||
self.booksDeleteButton.setEnabled(True)
|
||||
self.booksEditButton.setEnabled(True)
|
||||
|
@ -27,7 +27,6 @@
|
||||
import logging
|
||||
import os
|
||||
from lxml import etree, objectify
|
||||
from lxml.etree import Error, LxmlError
|
||||
import re
|
||||
|
||||
from openlp.core.lib import translate
|
||||
@ -82,44 +81,43 @@ class EasiSlidesImport(SongImport):
|
||||
|
||||
def _parse_song(self, song):
|
||||
self._success = True
|
||||
self._add_title(song)
|
||||
self._add_alttitle(song)
|
||||
self._add_number(song)
|
||||
self._add_title(self.title, song.Title1, True)
|
||||
self._add_alttitle(self.alternate_title, song.Title2)
|
||||
self._add_number(self.song_number, song.SongNumber)
|
||||
if self.song_number == u'0':
|
||||
self.song_number = u''
|
||||
self._add_authors(song)
|
||||
self._add_copyright(song)
|
||||
self._add_book(song)
|
||||
self._add_book(self.song_book_name, song.BookReference)
|
||||
self._parse_and_add_lyrics(song)
|
||||
return self._success
|
||||
|
||||
def _add_title(self, song):
|
||||
try:
|
||||
self.title = unicode(song.Title1).strip()
|
||||
except UnicodeDecodeError:
|
||||
log.exception(u'Unicode decode error while decoding Title1')
|
||||
self._success = False
|
||||
except AttributeError:
|
||||
log.exception(u'no Title1')
|
||||
self._success = False
|
||||
def _add_unicode_attribute(self, self_attribute, import_attribute,
|
||||
mandatory=False):
|
||||
"""
|
||||
Add imported values to the song model converting them to unicode at the
|
||||
same time. If the unicode decode fails or a mandatory attribute is not
|
||||
present _success is set to False so the importer can react
|
||||
appropriately.
|
||||
|
||||
def _add_alttitle(self, song):
|
||||
try:
|
||||
self.alternate_title = unicode(song.Title2).strip()
|
||||
except UnicodeDecodeError:
|
||||
log.exception(u'Unicode decode error while decoding Title2')
|
||||
self._success = False
|
||||
except AttributeError:
|
||||
pass
|
||||
``self_attribute``
|
||||
The attribute in the song model to populate.
|
||||
|
||||
def _add_number(self, song):
|
||||
``import_attribute``
|
||||
The imported value to convert to unicode and save to the song.
|
||||
|
||||
``mandatory``
|
||||
Signals that this attribute must exist in a valid song.
|
||||
"""
|
||||
try:
|
||||
number = unicode(song.SongNumber)
|
||||
if number != u'0':
|
||||
self.song_number = number
|
||||
self_attribute = unicode(import_attribute).strip()
|
||||
except UnicodeDecodeError:
|
||||
log.exception(u'Unicode decode error while decoding SongNumber')
|
||||
log.exception(u'UnicodeDecodeError decoding %s' % import_attribute)
|
||||
self._success = False
|
||||
except AttributeError:
|
||||
pass
|
||||
log.exception(u'No attribute %s' % import_attribute)
|
||||
if mandatory:
|
||||
self._success = False
|
||||
|
||||
def _add_authors(self, song):
|
||||
try:
|
||||
@ -159,15 +157,6 @@ class EasiSlidesImport(SongImport):
|
||||
pass
|
||||
self.add_copyright(u' '.join(copyright))
|
||||
|
||||
def _add_book(self, song):
|
||||
try:
|
||||
self.song_book_name = unicode(song.BookReference).strip()
|
||||
except UnicodeDecodeError:
|
||||
log.exception(u'Unicode decode error while decoding BookReference')
|
||||
self._success = False
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def _parse_and_add_lyrics(self, song):
|
||||
try:
|
||||
lyrics = unicode(song.Contents).strip()
|
||||
@ -313,7 +302,6 @@ class EasiSlidesImport(SongImport):
|
||||
tag = SeqTypes[tag.lower()]
|
||||
else:
|
||||
continue
|
||||
|
||||
if tag in versetags:
|
||||
self.verse_order_list.append(tag)
|
||||
else:
|
||||
|
@ -157,7 +157,6 @@ class SongMediaItem(MediaManagerItem):
|
||||
(5, u':/slides/slide_theme.png',
|
||||
translate('SongsPlugin.MediaItem', 'Themes'))
|
||||
])
|
||||
|
||||
self.configUpdated()
|
||||
|
||||
def onSearchTextButtonClick(self):
|
||||
@ -269,8 +268,8 @@ class SongMediaItem(MediaManagerItem):
|
||||
def onImportClick(self):
|
||||
if not hasattr(self, u'import_wizard'):
|
||||
self.import_wizard = SongImportForm(self, self.parent)
|
||||
self.import_wizard.exec_()
|
||||
Receiver.send_message(u'songs_load_list')
|
||||
if self.import_wizard.exec_() == QtGui.QDialog.Accepted:
|
||||
Receiver.send_message(u'songs_load_list')
|
||||
|
||||
def onNewClick(self):
|
||||
log.debug(u'onNewClick')
|
||||
|
@ -29,6 +29,7 @@ import os
|
||||
from PyQt4 import QtCore
|
||||
|
||||
from openlp.core.lib import Receiver
|
||||
from openlp.core.utils import get_uno_command, get_uno_instance
|
||||
from songimport import SongImport
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -61,7 +62,6 @@ class OooImport(SongImport):
|
||||
self.document = None
|
||||
self.process_started = False
|
||||
self.filenames = kwargs[u'filenames']
|
||||
self.uno_connection_type = u'pipe' #u'socket'
|
||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||
QtCore.SIGNAL(u'openlp_stop_wizard'), self.stop_import)
|
||||
|
||||
@ -105,25 +105,18 @@ class OooImport(SongImport):
|
||||
context = uno.getComponentContext()
|
||||
resolver = context.ServiceManager.createInstanceWithContext(
|
||||
u'com.sun.star.bridge.UnoUrlResolver', context)
|
||||
ctx = None
|
||||
uno_instance = None
|
||||
loop = 0
|
||||
while ctx is None and loop < 5:
|
||||
while uno_instance is None and loop < 5:
|
||||
try:
|
||||
if self.uno_connection_type == u'pipe':
|
||||
ctx = resolver.resolve(u'uno:' \
|
||||
+ u'pipe,name=openlp_pipe;' \
|
||||
+ u'urp;StarOffice.ComponentContext')
|
||||
else:
|
||||
ctx = resolver.resolve(u'uno:' \
|
||||
+ u'socket,host=localhost,port=2002;' \
|
||||
+ u'urp;StarOffice.ComponentContext')
|
||||
uno_instance = get_uno_instance(resolver)
|
||||
except:
|
||||
log.exception("Failed to resolve uno connection")
|
||||
self.start_ooo_process()
|
||||
loop += 1
|
||||
manager = ctx.ServiceManager
|
||||
self.start_ooo_process()
|
||||
loop += 1
|
||||
manager = uno_instance.ServiceManager
|
||||
self.desktop = manager.createInstanceWithContext(
|
||||
"com.sun.star.frame.Desktop", ctx)
|
||||
"com.sun.star.frame.Desktop", uno_instance)
|
||||
|
||||
def start_ooo_process(self):
|
||||
try:
|
||||
@ -132,14 +125,7 @@ class OooImport(SongImport):
|
||||
self.manager._FlagAsMethod(u'Bridge_GetStruct')
|
||||
self.manager._FlagAsMethod(u'Bridge_GetValueObject')
|
||||
else:
|
||||
if self.uno_connection_type == u'pipe':
|
||||
cmd = u'openoffice.org -nologo -norestore -minimized ' \
|
||||
+ u'-invisible -nofirststartwizard ' \
|
||||
+ u'-accept=pipe,name=openlp_pipe;urp;'
|
||||
else:
|
||||
cmd = u'openoffice.org -nologo -norestore -minimized ' \
|
||||
+ u'-invisible -nofirststartwizard ' \
|
||||
+ u'-accept=socket,host=localhost,port=2002;urp;'
|
||||
cmd = get_uno_command()
|
||||
process = QtCore.QProcess()
|
||||
process.startDetached(cmd)
|
||||
process.waitForStarted()
|
||||
|
@ -61,17 +61,18 @@ class OpenLyricsImport(SongImport):
|
||||
Imports the songs.
|
||||
"""
|
||||
self.import_wizard.progressBar.setMaximum(len(self.import_source))
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
for file_path in self.import_source:
|
||||
if self.stop_import_flag:
|
||||
return False
|
||||
self.import_wizard.incrementProgressBar(unicode(translate(
|
||||
'SongsPlugin.OpenLyricsImport', 'Importing %s...')) %
|
||||
os.path.basename(file_path))
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
parsed_file = etree.parse(file_path, parser)
|
||||
xml = unicode(etree.tostring(parsed_file))
|
||||
if self.openLyrics.xml_to_song(xml) is None:
|
||||
log.debug(u'File could not be imported: %s' % file_path)
|
||||
# Importing this song failed! For now we stop import.
|
||||
return False
|
||||
try:
|
||||
parsed_file = etree.parse(file_path, parser)
|
||||
xml = unicode(etree.tostring(parsed_file))
|
||||
if self.openLyrics.xml_to_song(xml) is None:
|
||||
log.debug(u'File could not be imported: %s' % file_path)
|
||||
except etree.XMLSyntaxError:
|
||||
log.exception(u'XML syntax error in file %s' % file_path)
|
||||
return True
|
||||
|
@ -197,16 +197,24 @@ class SongImport(QtCore.QObject):
|
||||
return
|
||||
self.media_files.append(filename)
|
||||
|
||||
def add_verse(self, verse, versetag=u'V'):
|
||||
def add_verse(self, versetext, versetag=u'V', lang=None):
|
||||
"""
|
||||
Add a verse. This is the whole verse, lines split by \n
|
||||
Verse tag can be V1/C1/B etc, or 'V' and 'C' (will count the verses/
|
||||
choruses itself) or None, where it will assume verse
|
||||
It will also attempt to detect duplicates. In this case it will just
|
||||
add to the verse order
|
||||
Add a verse. This is the whole verse, lines split by \n. It will also
|
||||
attempt to detect duplicates. In this case it will just add to the verse
|
||||
order.
|
||||
|
||||
``versetext``
|
||||
The text of the verse.
|
||||
|
||||
``versetag``
|
||||
The verse tag can be V1/C1/B etc, or 'V' and 'C' (will count the
|
||||
verses/choruses itself) or None, where it will assume verse.
|
||||
|
||||
``lang``
|
||||
The language code (ISO-639) of the verse, for example *en* or *de*.
|
||||
"""
|
||||
for (oldversetag, oldverse) in self.verses:
|
||||
if oldverse.strip() == verse.strip():
|
||||
for (oldversetag, oldverse, oldlang) in self.verses:
|
||||
if oldverse.strip() == versetext.strip():
|
||||
self.verse_order_list.append(oldversetag)
|
||||
return
|
||||
if versetag[0] in self.versecounts:
|
||||
@ -217,7 +225,7 @@ class SongImport(QtCore.QObject):
|
||||
versetag += unicode(self.versecounts[versetag[0]])
|
||||
elif int(versetag[1:]) > self.versecounts[versetag[0]]:
|
||||
self.versecounts[versetag[0]] = int(versetag[1:])
|
||||
self.verses.append([versetag, verse.rstrip()])
|
||||
self.verses.append([versetag, versetext.rstrip(), lang])
|
||||
self.verse_order_list.append(versetag)
|
||||
if versetag.startswith(u'V') and self.contains_verse(u'C1'):
|
||||
self.verse_order_list.append(u'C1')
|
||||
@ -266,7 +274,7 @@ class SongImport(QtCore.QObject):
|
||||
verses_changed_to_other = {}
|
||||
sxml = SongXML()
|
||||
other_count = 1
|
||||
for (versetag, versetext) in self.verses:
|
||||
for (versetag, versetext, lang) in self.verses:
|
||||
if versetag[0] == u'C':
|
||||
versetype = VerseType.to_string(VerseType.Chorus)
|
||||
elif versetag[0] == u'V':
|
||||
@ -286,7 +294,7 @@ class SongImport(QtCore.QObject):
|
||||
versetype = VerseType.to_string(VerseType.Other)
|
||||
log.info(u'Versetype %s changing to %s' , versetag, newversetag)
|
||||
versetag = newversetag
|
||||
sxml.add_verse_to_lyrics(versetype, versetag[1:], versetext)
|
||||
sxml.add_verse_to_lyrics(versetype, versetag[1:], versetext, lang)
|
||||
song.search_lyrics += u' ' + self.remove_punctuation(versetext)
|
||||
song.search_lyrics = song.search_lyrics.lower()
|
||||
song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
|
||||
@ -338,7 +346,7 @@ class SongImport(QtCore.QObject):
|
||||
+ u'========================================'
|
||||
print u'TITLE: ' + self.title
|
||||
print u'ALT TITLE: ' + self.alternate_title
|
||||
for (versetag, versetext) in self.verses:
|
||||
for (versetag, versetext, lang) in self.verses:
|
||||
print u'VERSE ' + versetag + u': ' + versetext
|
||||
print u'ORDER: ' + u' '.join(self.verse_order_list)
|
||||
for author in self.authors:
|
||||
|
@ -31,7 +31,7 @@ The basic XML for storing the lyrics in the song database is of the format::
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<song version="1.0">
|
||||
<lyrics>
|
||||
<verse type="chorus" label="1">
|
||||
<verse type="Chorus" label="1" lang="en">
|
||||
<![CDATA[ ... ]]>
|
||||
</verse>
|
||||
</lyrics>
|
||||
@ -84,7 +84,7 @@ class SongXML(object):
|
||||
self.song_xml = objectify.fromstring(u'<song version="1.0" />')
|
||||
self.lyrics = etree.SubElement(self.song_xml, u'lyrics')
|
||||
|
||||
def add_verse_to_lyrics(self, type, number, content):
|
||||
def add_verse_to_lyrics(self, type, number, content, lang=None):
|
||||
"""
|
||||
Add a verse to the *<lyrics>* tag.
|
||||
|
||||
@ -97,9 +97,15 @@ class SongXML(object):
|
||||
|
||||
``content``
|
||||
The actual text of the verse to be stored.
|
||||
|
||||
``lang``
|
||||
The verse's language code (ISO-639). This is not required, but
|
||||
should be added if available.
|
||||
"""
|
||||
verse = etree.Element(u'verse', type=unicode(type),
|
||||
label=unicode(number))
|
||||
if lang:
|
||||
verse.set(u'lang', lang)
|
||||
verse.text = etree.CDATA(content)
|
||||
self.lyrics.append(verse)
|
||||
|
||||
@ -117,6 +123,11 @@ class SongXML(object):
|
||||
|
||||
``xml``
|
||||
The XML of the song to be parsed.
|
||||
|
||||
The returned list has the following format::
|
||||
|
||||
[[{'lang': 'en', 'type': 'V', 'label': '1'}, u"The English verse."],
|
||||
[{'lang': 'en', 'type': 'C', 'label': '1'}, u"The English chorus."]]
|
||||
"""
|
||||
self.song_xml = None
|
||||
if xml[:5] == u'<?xml':
|
||||
@ -196,7 +207,7 @@ class OpenLyrics(object):
|
||||
This property is not supported.
|
||||
|
||||
*<verse name="v1a" lang="he" translit="en">*
|
||||
The attribute *translit* and *lang* are not supported.
|
||||
The attribute *translit* is not supported.
|
||||
|
||||
*<verseOrder>*
|
||||
OpenLP supports this property.
|
||||
@ -268,13 +279,16 @@ class OpenLyrics(object):
|
||||
# No xml get out of here.
|
||||
if not xml:
|
||||
return None
|
||||
song = Song()
|
||||
if xml[:5] == u'<?xml':
|
||||
xml = xml[38:]
|
||||
# Remove chords from xml.
|
||||
xml = re.compile(u'<chord name=".*?"/>').sub(u'', xml)
|
||||
song_xml = objectify.fromstring(xml)
|
||||
properties = song_xml.properties
|
||||
try:
|
||||
properties = song_xml.properties
|
||||
except AttributeError:
|
||||
return None
|
||||
song = Song()
|
||||
self._process_copyright(properties, song)
|
||||
self._process_cclinumber(properties, song)
|
||||
self._process_titles(properties, song)
|
||||
@ -442,7 +456,10 @@ class OpenLyrics(object):
|
||||
if not verse_number:
|
||||
verse_number = u'1'
|
||||
temp_verse_order.append((verse_type, verse_number, verse_part))
|
||||
sxml.add_verse_to_lyrics(verse_type, verse_number, text)
|
||||
lang = None
|
||||
if self._get(verse, u'lang'):
|
||||
lang = self._get(verse, u'lang')
|
||||
sxml.add_verse_to_lyrics(verse_type, verse_number, text, lang)
|
||||
search_text = search_text + text
|
||||
song.search_lyrics = search_text.lower()
|
||||
song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
|
||||
|
@ -134,7 +134,7 @@ class SongsPlugin(Plugin):
|
||||
|
||||
def onToolsReindexItemTriggered(self):
|
||||
"""
|
||||
Rebuild the search title of each song.
|
||||
Rebuild each song.
|
||||
"""
|
||||
maxSongs = self.manager.get_object_count(Song)
|
||||
progressDialog = QtGui.QProgressDialog(
|
||||
@ -150,8 +150,13 @@ class SongsPlugin(Plugin):
|
||||
song.title = u''
|
||||
if song.alternate_title is None:
|
||||
song.alternate_title = u''
|
||||
song.search_title = self.whitespace.sub(u' ', song.title.lower() + \
|
||||
song.search_title = self.whitespace.sub(u' ', song.title.lower() +
|
||||
u' ' + song.alternate_title.lower())
|
||||
# Remove the "language" attribute from lyrics tag. This is not very
|
||||
# important, but this keeps the database clean. This can be removed
|
||||
# when everybody has run the reindex tool once.
|
||||
song.lyrics = song.lyrics.replace(
|
||||
u'<lyrics language="en">', u'<lyrics>')
|
||||
lyrics = u''
|
||||
verses = SongXML().get_verses(song.lyrics)
|
||||
for verse in verses:
|
||||
@ -159,8 +164,7 @@ class SongsPlugin(Plugin):
|
||||
song.search_lyrics = lyrics.lower()
|
||||
progressDialog.setValue(counter)
|
||||
self.manager.save_objects(songs)
|
||||
counter += 1
|
||||
progressDialog.setValue(counter)
|
||||
progressDialog.setValue(counter + 1)
|
||||
self.mediaItem.displayResultsSong(
|
||||
self.manager.get_all_objects(Song, order_by_ref=Song.search_title))
|
||||
|
||||
|
2690
resources/i18n/af.ts
2690
resources/i18n/af.ts
File diff suppressed because it is too large
Load Diff
4090
resources/i18n/de.ts
4090
resources/i18n/de.ts
File diff suppressed because it is too large
Load Diff
2525
resources/i18n/en.ts
2525
resources/i18n/en.ts
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2548
resources/i18n/es.ts
2548
resources/i18n/es.ts
File diff suppressed because it is too large
Load Diff
2957
resources/i18n/et.ts
2957
resources/i18n/et.ts
File diff suppressed because it is too large
Load Diff
2579
resources/i18n/hu.ts
2579
resources/i18n/hu.ts
File diff suppressed because it is too large
Load Diff
3491
resources/i18n/ja.ts
3491
resources/i18n/ja.ts
File diff suppressed because it is too large
Load Diff
2541
resources/i18n/ko.ts
2541
resources/i18n/ko.ts
File diff suppressed because it is too large
Load Diff
2544
resources/i18n/nb.ts
2544
resources/i18n/nb.ts
File diff suppressed because it is too large
Load Diff
5159
resources/i18n/nl.ts
Normal file
5159
resources/i18n/nl.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2608
resources/i18n/sv.ts
2608
resources/i18n/sv.ts
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user