Compare commits

...

12 Commits

Author SHA1 Message Date
Charles Crossan 0717e49b46 Merge branch 'feature/add-countdown-timer' into 'master'
WIP: Feature/add countdown timer

See merge request openlp/openlp!29
2024-04-27 17:26:24 +00:00
Raoul Snyman 6bbfe00ec0 Merge branch 'translations-21042024' into 'master'
Translations 21042024

See merge request openlp/openlp!748
2024-04-27 05:42:58 +00:00
Tim Bentley cee0a9d573 Translations 21042024 2024-04-27 05:42:58 +00:00
Charles Crossan 6d6ba612c0 move the javascript to an external file instead of a string in python 2019-09-30 22:20:02 -04:00
Charles Crossan 18aa7c38a6 fix most of the linter errors 2019-09-30 22:19:40 -04:00
Charles Crossan 8fbe858004 update includes so that OLP starts without error 2019-09-30 18:40:38 -04:00
Charles Crossan 10af0507bc Merge branch 'master' into feature/add-countdown-timer 2019-09-30 17:41:06 -04:00
Charles Crossan 733fd0a057 built save and load to database code
Migrated from bzr 2462 at https://code.launchpad.net/~crossan007/openlp/countdowntimer
2019-09-30 17:39:31 -04:00
Charles Crossan 11d3350078 Built editcountdowndialog.py GUI
Migrated from bzr 2461 at https://code.launchpad.net/~crossan007/openlp/countdowntimer
2019-09-30 17:38:42 -04:00
Charles Crossan ee2e072856 various changes
Migrated from bzr 2460 at https://code.launchpad.net/~crossan007/openlp/countdowntimer
2019-09-30 17:37:46 -04:00
Charles Crossan 89ff005d57 Tweaked Settings
Migrated from bzr 2459 at https://code.launchpad.net/~crossan007/openlp/countdowntimer
2019-09-30 17:36:37 -04:00
Charles Crossan 362962a992 Added Countdown Plugin
Migrated from bzr 2458 at https://code.launchpad.net/~crossan007/openlp/countdowntimer
2019-09-30 17:35:21 -04:00
48 changed files with 14792 additions and 12090 deletions

View File

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
The :mod:`countdown` module provides the Countdown plugin which allows
themed countdown, timers to be displayed on the main screen
type.
"""

View File

@ -0,0 +1,177 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
# #
###############################################################################
# This file contains MIT licensed code #
###############################################################################
"""
The :mod:`~openlp.plugins.countdown.countdownplugin` module contains the Plugin class
for the Countdown plugin.
"""
import logging
from openlp.core.lib.plugin import Plugin, StringContent
from openlp.core.common.i18n import translate
from openlp.core.lib.db import Manager
from openlp.plugins.countdown.lib.countdowntab import CountdownTab
from openlp.plugins.countdown.lib.db import CountdownSlide, init_schema
from openlp.plugins.countdown.lib.mediaitem import CountdownMediaItem,CountdownSearch
from PyQt5 import QtGui, QtCore
log = logging.getLogger(__name__)
__default_settings__ = {
'countdown/db type': 'sqlite',
'countdown/last search type': CountdownSearch.Titles,
'countdown/display event name': True,
'countdown/display legend': True,
'shortcuts/listViewCountdownDeleteItem': [QtGui.QKeySequence(QtCore.Qt.Key_Delete)],
'shortcuts/listViewCountdownPreviewItem': [QtGui.QKeySequence(QtCore.Qt.Key_Enter),
QtGui.QKeySequence(QtCore.Qt.Key_Return)],
'shortcuts/listViewCountdownLiveItem': [QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Enter),
QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Return)],
'shortcuts/listViewCountdownServiceItem': [QtGui.QKeySequence(QtCore.Qt.Key_Plus),
QtGui.QKeySequence(QtCore.Qt.Key_Equal)],
}
class CountdownPlugin(Plugin):
"""
This plugin enables the user to create, edit and display countdown timers.
All Countdown timers have one slide, which is dynamically updated by JavaScript running in webkit.
The slide manager will display only one slide for all countdown items
with a textual representation of the countdown event
Examples include countdowns until: worship time, Christmas, Easter.
Examples do not include countdowns until: judgement day.
"""
log.info('Countdown Plugin loaded')
def __init__(self):
super(CountdownPlugin, self).__init__('countdown', __default_settings__, CountdownMediaItem, CountdownTab)
self.weight = -1
self.db_manager = Manager('countdown', init_schema)
self.icon_path = ':/plugins/plugin_custom.png'
self.icon = self.icon_path
@staticmethod
def about(self):
about_text = translate('CountdownPlugin', '<strong>Countdown Plugin </strong><br />The countdown plugin '
'provides the ability to display a live countdown to an event')
return about_text
def uses_theme(self, theme):
"""
Called to find out if the countdown plugin is currently using a theme.
Returns True if the theme is being used, otherwise returns False.
"""
if self.db_manager.get_all_objects(CountdownSlide, CountdownSlide.theme_name == theme):
return True
return False
def rename_theme(self, old_theme, new_theme):
"""
Renames a theme the countdown plugin is using making the plugin use the new name.
:param old_theme: The name of the theme the plugin should stop using.
:param new_theme: The new name the plugin should now use.
"""
countdowns_using_theme = self.db_manager.get_all_objects(CountdownSlide, CountdownSlide.theme_name == old_theme)
for countdown in countdowns_using_theme:
countdown.theme_name = new_theme
self.db_manager.save_object(countdown)
def set_plugin_text_strings(self):
"""
Called to define all translatable texts of the plugin
"""
# Name PluginList
self.text_strings[StringContent.Name] = {
'singular': translate('CountdownPlugin', 'Countdown Slide', 'name singular'),
'plural': translate('CountdownPlugin', 'Countdown Slides', 'name plural')
}
# Name for MediaDockManager, SettingsManager
self.text_strings[StringContent.VisibleName] = {
'title': translate('CountdownPlugin', 'Countdown Slides', 'container title')
}
# Middle Header Bar
tooltips = {
'load': translate('CountdownPlugin', 'Load a new countdown slide.'),
'import': translate('CountdownPlugin', 'Import a countdown slide.'),
'new': translate('CountdownPlugin', 'Add a new countdown slide.'),
'edit': translate('CountdownPlugin', 'Edit the selected countdown slide.'),
'delete': translate('CountdownPlugin', 'Delete the selected countdown slide.'),
'preview': translate('CountdownPlugin', 'Preview the selected countdown slide.'),
'live': translate('CountdownPlugin', 'Send the selected countdown slide live.'),
'service': translate('CountdownPlugin', 'Add the selected countdown slide to the service.')
}
self.set_plugin_ui_text_strings(tooltips)
def finalise(self):
"""
Time to tidy up on exit
"""
log.info('Countdown Finalising')
self.db_manager.finalise()
Plugin.finalise(self)
def get_display_css(self):
"""
Add css style sheets to htmlbuilder.
Currently, countdowns use no custom CSS, but that will probably change, so lets build an empty class
"""
css = """
#countdowntext{
}
"""
return css
def get_display_javascript(self):
try:
countdownjs_file_path = AppLocation.get_directory(AppLocation.AppDir) / '..' / 'Resources' / 'countdown.js'
with countdownjs_file_path.open('r') as file_handle:
content = file_handle.read()
except (OSError):
log.exception('Failed to open text file {text}'.format(text=text_file_path))
return content
def get_display_html(self):
"""
Add html code to htmlbuilder.
"""
log.debug('Countdown get_display_html called')
HTML = """
<div id="countdown" class="lyricstable"><h1 id="countdowntext">test</h1></div>
"""
HTML = ""
return HTML

View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################

View File

@ -0,0 +1,228 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 PyQt5 import QtGui
from openlp.core.common.i18n import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
class Ui_CountdownEditDialog(object):
def setupUi(self, countdown_edit_dialog):
# Set up the main Window
countdown_edit_dialog.setObjectName("countdown_edit_dialog")
countdown_edit_dialog.setWindowIcon(build_icon(u':/icon/openlp-logo.svg'))
countdown_edit_dialog.resize(450, 350)
# Set up the main content layout
self.dialog_layout = QtGui.QVBoxLayout(countdown_edit_dialog)
self.dialog_layout.setObjectName('dialog_layout')
# Set up a layout for the title label and edit box
self.title_layout = QtGui.QHBoxLayout()
self.title_layout.setObjectName('title_layout')
self.title_label = QtGui.QLabel(countdown_edit_dialog)
self.title_label.setObjectName('title_label')
self.title_layout.addWidget(self.title_label)
self.title_edit = QtGui.QLineEdit(countdown_edit_dialog)
self.title_label.setBuddy(self.title_edit)
self.title_edit.setObjectName('title_edit')
self.title_layout.addWidget(self.title_edit)
self.dialog_layout.addLayout(self.title_layout)
# set up a layout for the countdown properties
self.central_layout = QtGui.QFormLayout()
self.central_layout.setObjectName('central_layout')
# build label for countdown_type
self.countdown_type_label = QtGui.QLabel(countdown_edit_dialog)
self.countdown_type_label.setObjectName("countdown_type_label")
# build countdown_type_combo_box combo box
self.countdown_type_combo_box = QtGui.QComboBox(countdown_edit_dialog)
self.countdown_type_combo_box.setObjectName("countdown_type_combo_box")
self.countdown_type_combo_box.addItem("")
self.countdown_type_combo_box.addItem("")
self.countdown_type_label.setBuddy(self.countdown_type_combo_box)
self.central_layout.addRow(self.countdown_type_label, self.countdown_type_combo_box)
# build label for countdown time
self.countdown_duration_label = QtGui.QLabel(countdown_edit_dialog)
self.countdown_duration_label.setObjectName("countdown_duration_label")
# build time edit box for countdown time
self.countdown_duration_time_edit = QtGui.QTimeEdit(countdown_edit_dialog)
self.countdown_duration_time_edit.setObjectName("countdown_duration_time_edit")
# add to layout
self.countdown_duration_label.setBuddy(self.countdown_duration_time_edit)
self.central_layout.addRow(self.countdown_duration_label, self.countdown_duration_time_edit)
# Build label for use_specific_date
self.use_specific_date_label = QtGui.QLabel(countdown_edit_dialog)
self.use_specific_date_label.setObjectName("use_specific_date_label")
# Build Check box for use_specific_date
self.use_specific_date_check_box = QtGui.QCheckBox(countdown_edit_dialog)
self.use_specific_date_check_box.setObjectName("use_specific_date_check_box")
# add use specific date to layout
self.use_specific_date_label.setBuddy(self.use_specific_date_check_box)
self.central_layout.addRow(self.use_specific_date_label, self.use_specific_date_check_box)
# build label for countdown date
self.countdown_date_label = QtGui.QLabel(countdown_edit_dialog)
self.countdown_date_label.setObjectName("countdown_date_label")
# build date edit box for countdown date
self.countdown_date_date_edit = QtGui.QDateEdit(countdown_edit_dialog)
self.countdown_date_date_edit.setObjectName("countdown_date_date_edit")
# add countdown date to layout
self.countdown_date_label.setBuddy(self.countdown_date_date_edit)
self.central_layout.addRow(self.countdown_date_label, self.countdown_date_date_edit)
# build label for use_specific_time_checkbox
self.use_specific_time_label = QtGui.QLabel(countdown_edit_dialog)
self.use_specific_time_label.setObjectName("use_specific_time_label")
# build use_specific_time_checkbox
self.use_specific_time_check_box = QtGui.QCheckBox(countdown_edit_dialog)
self.use_specific_time_check_box.setObjectName("use_specific_time_check_box")
# add to layout
self.use_specific_time_label.setBuddy(self.use_specific_time_check_box)
self.central_layout.addRow(self.use_specific_time_label, self.use_specific_time_check_box)
# build label for countdown time
self.countdown_time_label = QtGui.QLabel(countdown_edit_dialog)
self.countdown_time_label.setObjectName("countdown_time_label")
# build time edit box for countdown time
self.countdown_time_time_edit = QtGui.QTimeEdit(countdown_edit_dialog)
self.countdown_time_time_edit.setObjectName("countdown_time_time_edit")
# add to layout
self.countdown_time_label.setBuddy(self.countdown_time_time_edit)
self.central_layout.addRow(self.countdown_time_label, self.countdown_time_time_edit)
# build label for interval_large
self.interval_large_label = QtGui.QLabel(countdown_edit_dialog)
self.interval_large_label.setObjectName("interval_large_label")
# build interval_large combo box
self.interval_large_combo_box = QtGui.QComboBox(countdown_edit_dialog)
self.interval_large_combo_box.setObjectName("interval_large_combo_box")
self.interval_large_combo_box.addItem("")
self.interval_large_combo_box.addItem("")
self.interval_large_combo_box.addItem("")
self.interval_large_combo_box.addItem("")
self.interval_large_combo_box.addItem("")
self.interval_large_combo_box.addItem("")
self.interval_large_combo_box.addItem("")
self.interval_large_combo_box.addItem("")
# add to layout
self.interval_large_label.setBuddy(self.interval_large_combo_box)
self.central_layout.addRow(self.interval_large_label, self.interval_large_combo_box)
# build label for interval small
self.interval_small_label = QtGui.QLabel(countdown_edit_dialog)
self.interval_small_label.setObjectName("interval_small_label")
# build interval_small_combo_box
self.interval_small_combo_box = QtGui.QComboBox(countdown_edit_dialog)
self.interval_small_combo_box.setObjectName("interval_small_combo_box")
self.interval_small_combo_box.addItem("")
self.interval_small_combo_box.addItem("")
self.interval_small_combo_box.addItem("")
self.interval_small_combo_box.addItem("")
self.interval_small_combo_box.addItem("")
self.interval_small_combo_box.addItem("")
self.interval_small_combo_box.addItem("")
self.interval_small_combo_box.addItem("")
# add to layout
self.interval_small_label.setBuddy(self.interval_small_combo_box)
self.central_layout.addRow(self.interval_small_label, self.interval_small_combo_box)
# build label for finish_action
self.finish_action_label = QtGui.QLabel(countdown_edit_dialog)
self.finish_action_label.setObjectName("finish_action_label")
# build finish_action_combo_box
self.finish_action_combo_box = QtGui.QComboBox(countdown_edit_dialog)
self.finish_action_combo_box.setObjectName("finish_action_combo_box")
self.finish_action_combo_box.addItem("")
self.finish_action_combo_box.addItem("")
self.finish_action_combo_box.addItem("")
self.finish_action_label.setBuddy(self.finish_action_combo_box)
self.central_layout.addRow(self.finish_action_label, self.finish_action_combo_box)
# add the central_layout to the dialog_layout
self.dialog_layout.addLayout(self.central_layout)
# create the bottom layout
self.bottom_form_layout = QtGui.QFormLayout()
self.bottom_form_layout.setObjectName('bottom_form_layout')
self.theme_label = QtGui.QLabel(countdown_edit_dialog)
self.theme_label.setObjectName('theme_label')
self.theme_combo_box = QtGui.QComboBox(countdown_edit_dialog)
self.theme_combo_box.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
self.theme_combo_box.setObjectName('theme_combo_box')
self.theme_label.setBuddy(self.theme_combo_box)
self.bottom_form_layout.addRow(self.theme_label, self.theme_combo_box)
# add the bottom_layout to the dialog_layout
self.dialog_layout.addLayout(self.bottom_form_layout)
# Create the cancel, save button box, and add it to the dialog_layout
self.button_box = create_button_box(countdown_edit_dialog, 'button_box', ['cancel', 'save'])
self.dialog_layout.addWidget(self.button_box)
# retranslate the UI
self.retranslateUi(countdown_edit_dialog)
def retranslateUi(self, countdown_edit_dialog):
countdown_edit_dialog.setWindowTitle(translate("customEditDialog", "Edit Countdown Slides", None))
self.theme_label.setText(translate("customEditDialog", "Theme:", None))
self.title_label.setText(translate("customEditDialog", "Title:", None))
self.countdown_type_label.setText(translate("customEditDialog", "Countdown Type", None))
self.countdown_type_combo_box.setItemText(0, translate("customEditDialog", "Future Date / Time", None))
self.countdown_type_combo_box.setItemText(1, translate("customEditDialog", "Specific Duration", None))
self.countdown_duration_label.setText(translate("customEditDialog", "Countdown Duration", None))
self.use_specific_date_label.setText(translate("customEditDialog", "Use Specific Date", None))
self.countdown_date_label.setText(translate("customEditDialog", "Countdown Date", None))
self.use_specific_time_label.setText(translate("customEditDialog", "Use Specific Time", None))
self.countdown_time_label.setText(translate("customEditDialog", "Countdown Time", None))
self.interval_large_label.setText(translate("customEditDialog", "Largest Interval to Display", None))
self.interval_large_combo_box.setItemText(0, translate("customEditDialog", "Years", None))
self.interval_large_combo_box.setItemText(1, translate("customEditDialog", "Months", None))
self.interval_large_combo_box.setItemText(2, translate("customEditDialog", "Weeks", None))
self.interval_large_combo_box.setItemText(3, translate("customEditDialog", "Days", None))
self.interval_large_combo_box.setItemText(4, translate("customEditDialog", "Hours", None))
self.interval_large_combo_box.setItemText(5, translate("customEditDialog", "Minues", None))
self.interval_large_combo_box.setItemText(6, translate("customEditDialog", "Seconds", None))
self.interval_large_combo_box.setItemText(7, translate("customEditDialog", "Miliseconds", None))
self.interval_small_label.setText(translate("customEditDialog", "Smallest Interval to Display", None))
self.interval_small_combo_box.setItemText(0, translate("customEditDialog", "Years", None))
self.interval_small_combo_box.setItemText(1, translate("customEditDialog", "Months", None))
self.interval_small_combo_box.setItemText(2, translate("customEditDialog", "Weeks", None))
self.interval_small_combo_box.setItemText(3, translate("customEditDialog", "Days", None))
self.interval_small_combo_box.setItemText(4, translate("customEditDialog", "Hours", None))
self.interval_small_combo_box.setItemText(5, translate("customEditDialog", "Minues", None))
self.interval_small_combo_box.setItemText(6, translate("customEditDialog", "Seconds", None))
self.interval_small_combo_box.setItemText(7, translate("customEditDialog", "Miliseconds", None))
self.finish_action_label.setText(translate("customEditDialog", "Finish Action", None))
self.finish_action_combo_box.setItemText(0, translate("customEditDialog", "Blink", None))
self.finish_action_combo_box.setItemText(1, translate("customEditDialog", "Blank", None))
self.finish_action_combo_box.setItemText(2, translate("customEditDialog", "Next Slide", None))

View File

@ -0,0 +1,287 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
import logging
from PyQt5 import QtGui
from PyQt5.QtWidgets import QDialog
from openlp.core.common.i18n import translate
from openlp.core.common.registry import Registry
from openlp.core.lib.ui import critical_error_message_box
from openlp.plugins.countdown.lib.db import CountdownSlide
from .editcountdowndialog import Ui_CountdownEditDialog
# from .editcountdownslideform import EditCountdownSlideForm
log = logging.getLogger(__name__)
class EditCountdownForm(QDialog, Ui_CountdownEditDialog):
"""
Class documentation goes here.
"""
log.info('Countdown Editor loaded')
def __init__(self, media_item, parent, manager):
"""
Constructor
"""
super(EditCountdownForm, self).__init__(parent)
self.manager = manager
self.media_item = media_item
self.setupUi(self)
# Create other objects and forms.
# self.edit_slide_form = EditCountdownSlideForm(self)
# Connecting signals and slots
# self.preview_button.clicked.connect(self.on_preview_button_clicked)
# self.add_button.clicked.connect(self.on_add_button_clicked)
# self.edit_button.clicked.connect(self.on_edit_button_clicked)
# self.edit_all_button.clicked.connect(self.on_edit_all_button_clicked)
# self.slide_list_view.currentRowChanged.connect(self.on_current_row_changed)
# self.slide_list_view.doubleClicked.connect(self.on_edit_button_clicked)
Registry().register_function('theme_update_list', self.load_themes)
def load_themes(self, theme_list):
"""
Load a list of themes into the themes combo box.
:param theme_list: The list of themes to load.
"""
self.theme_combo_box.clear()
self.theme_combo_box.addItem('')
self.theme_combo_box.addItems(theme_list)
def load_countdown(self, id, preview=False):
"""
Called when editing or creating a new countdown.
:param id: The countdown's id. If zero, then a new countdown is created
"""
if id == 0:
self.countdown_slide = CountdownSlide()
self.title_edit.setText('')
self.theme_combo_box.setCurrentIndex(0)
else:
self.countdown_slide = self.manager.get_object(CountdownSlide, id)
self.title_edit.setText(self.countdown_slide.title)
self.countdown_type_combo_box.setCurrentIndex(self.countdown_slide.countdown_type)
if self.countdown_slide.countdown_type == 1:
self.countdown_duration_time_edit.setTime(self.countdown_slide.countdown_duration)
else:
if self.countdown_slide.countdown_use_specific_date:
self.use_specific_date_check_box.setChecked(True)
self.countdown_date_date_edit.setDate(self.countdown_slide.countdown_specific_date)
if self.countdown_slide.countdown_use_specific_time:
self.use_specific_time_check_box.setChecked(True)
self.countdown_time_time_edit.setTime(self.countdown_slide.countdown_specific_time)
self.interval_large_combo_box.setCurrentIndex(self.countdown_slide.interval_large)
self.interval_small_combo_box.setCurrentIndex(self.countdown_slide.interval_small)
self.finish_action_combo_box.setCurrentIndex(self.countdown_slide.finish_action)
self.countdown_slide.theme_name = self.theme_combo_box.currentText()
self.media_item.auto_select_id = self.countdown_slide.id
# theme = self.countdown_slide.theme_name
# find_and_set_in_combo_box(self.theme_combo_box, theme)
self.title_edit.setFocus()
log.debug('load successful')
def accept(self):
"""
Override the QDialog method to check if the countdown slide has been saved before closing the dialog.
"""
log.debug('accept')
if self.save_countdown():
QtGui.QDialog.accept(self)
log.debug('Save successful')
def save_countdown(self):
"""
Saves the countdown.
"""
if not self._validate():
return False
# sxml = CountdownXMLBuilder()
# for count in range(self.slide_list_view.count()):
# sxml.add_verse_to_lyrics('countdown', str(count + 1), self.slide_list_view.item(count).text())
self.countdown_slide.title = self.title_edit.text()
self.countdown_slide.countdown_type = self.countdown_type_combo_box.currentIndex()
if self.countdown_slide.countdown_type == 1:
self.countdown_slide.countdown_duration = self.countdown_duration_time_edit.time().toPyTime()
else:
self.countdown_slide.countdown_use_specific_date = self.use_specific_date_check_box.isChecked()
if self.countdown_slide.countdown_use_specific_date:
self.countdown_slide.countdown_specific_date = self.countdown_date_date_edit.date().toPyDate()
self.countdown_slide.countdown_use_specific_time = self.use_specific_time_check_box.isChecked()
if self.countdown_slide.countdown_use_specific_time:
self.countdown_slide.countdown_specific_time = self.countdown_time_time_edit.time().toPyTime()
self.countdown_slide.interval_large = self.interval_large_combo_box.currentIndex()
self.countdown_slide.interval_small = self.interval_small_combo_box.currentIndex()
self.countdown_slide.finish_action = self.finish_action_combo_box.currentIndex()
self.countdown_slide.theme_name = self.theme_combo_box.currentText()
self.media_item.auto_select_id = self.countdown_slide.id
success = self.manager.save_object(self.countdown_slide)
return success
def on_up_button_clicked(self):
"""
Move a slide up in the list when the "Up" button is clicked.
selected_row = self.slide_list_view.currentRow()
if selected_row != 0:
qw = self.slide_list_view.takeItem(selected_row)
self.slide_list_view.insertItem(selected_row - 1, qw)
self.slide_list_view.setCurrentRow(selected_row - 1)
"""
def on_down_button_clicked(self):
"""
Move a slide down in the list when the "Down" button is clicked.
selected_row = self.slide_list_view.currentRow()
# zero base arrays
if selected_row != self.slide_list_view.count() - 1:
qw = self.slide_list_view.takeItem(selected_row)
self.slide_list_view.insertItem(selected_row + 1, qw)
self.slide_list_view.setCurrentRow(selected_row + 1)
"""
def on_add_button_clicked(self):
"""
Add a new blank slide.
self.edit_slide_form.set_text('')
if self.edit_slide_form.exec_():
self.slide_list_view.addItems(self.edit_slide_form.get_text())
"""
def on_edit_button_clicked(self):
"""
Edit the currently selected slide.
self.edit_slide_form.set_text(self.slide_list_view.currentItem().text())
if self.edit_slide_form.exec_():
self.update_slide_list(self.edit_slide_form.get_text())
"""
def on_edit_all_button_clicked(self):
"""
Edits all slides.
slide_text = ''
for row in range(self.slide_list_view.count()):
item = self.slide_list_view.item(row)
slide_text += item.text()
if row != self.slide_list_view.count() - 1:
slide_text += '\n[===]\n'
self.edit_slide_form.set_text(slide_text)
if self.edit_slide_form.exec_():
self.update_slide_list(self.edit_slide_form.get_text(), True)
"""
def on_preview_button_clicked(self):
"""
Save the countdown item and preview it.
log.debug('onPreview')
if self.save_countdown():
Registry().execute('countdown_preview')
"""
def update_slide_list(self, slides, edit_all=False):
"""
Updates the slide list after editing slides.
:param slides: A list of all slides which have been edited.
:param edit_all: Indicates if all slides or only one slide has been edited.
if edit_all:
self.slide_list_view.clear()
self.slide_list_view.addItems(slides)
else:
old_row = self.slide_list_view.currentRow()
# Create a list with all (old/unedited) slides.
old_slides = [self.slide_list_view.item(row).text() for row in range(self.slide_list_view.count())]
self.slide_list_view.clear()
old_slides.pop(old_row)
# Insert all slides to make the old_slides list complete.
for slide in slides:
old_slides.insert(old_row, slide)
self.slide_list_view.addItems(old_slides)
self.slide_list_view.repaint()
"""
def on_delete_button_clicked(self):
"""
Removes the current row from the list.
self.slide_list_view.takeItem(self.slide_list_view.currentRow())
self.on_current_row_changed(self.slide_list_view.currentRow())
"""
def on_current_row_changed(self, row):
"""
Called when the *slide_list_view*'s current row has been changed. This
enables or disables buttons which require an slide to act on.
:param row: The row (int). If there is no current row, the value is -1.
if row == -1:
self.delete_button.setEnabled(False)
self.edit_button.setEnabled(False)
self.up_button.setEnabled(False)
self.down_button.setEnabled(False)
else:
self.delete_button.setEnabled(True)
self.edit_button.setEnabled(True)
# Decide if the up/down buttons should be enabled or not.
self.down_button.setEnabled(self.slide_list_view.count() - 1 != row)
self.up_button.setEnabled(row != 0)
"""
def _validate(self):
"""
Checks whether a countdown is valid or not.
"""
# We must have a title.
if not self.title_edit.displayText():
self.title_edit.setFocus()
critical_error_message_box(message=translate('CountdownPlugin.EditCountdownForm', 'You need to type in a title.'))
return False
# We must have at least one slide.
# if self.slide_list_view.count() == 0:
# critical_error_message_box(message=translate('CountdownPlugin.EditCountdownForm',
# 'You need to add at least one slide.'))
# return False
return True

View File

@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 PyQt5 import QtWidgets
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.widgets.edits import SpellTextEdit
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button, create_button_box
class Ui_CountdownSlideEditDialog(object):
def setupUi(self, countdown_slide_edit_dialog):
countdown_slide_edit_dialog.setObjectName('countdown_slide_edit_dialog')
countdown_slide_edit_dialog.setWindowIcon(build_icon(u':/icon/openlp-logo.svg'))
countdown_slide_edit_dialog.resize(350, 300)
self.dialog_layout = QtWidgets.QVBoxLayout(countdown_slide_edit_dialog)
self.slide_text_edit = SpellTextEdit(self)
self.slide_text_edit.setObjectName('slide_text_edit')
self.dialog_layout.addWidget(self.slide_text_edit)
self.split_button = create_button(countdown_slide_edit_dialog, 'splitButton', icon=':/general/general_add.png')
self.insert_button = create_button(countdown_slide_edit_dialog, 'insertButton',
icon=':/general/general_add.png')
self.button_box = create_button_box(countdown_slide_edit_dialog, 'button_box', ['cancel', 'save'],
[self.split_button, self.insert_button])
self.dialog_layout.addWidget(self.button_box)
self.retranslateUi(countdown_slide_edit_dialog)
def retranslateUi(self, countdown_slide_edit_dialog):
countdown_slide_edit_dialog.setWindowTitle(translate('CountdownPlugin.EditVerseForm', 'Edit Slide'))
self.split_button.setText(UiStrings().Split)
self.split_button.setToolTip(UiStrings().SplitToolTip)
self.insert_button.setText(translate('CountdownPlugin.EditCountdownForm', 'Insert Slide'))
self.insert_button.setToolTip(translate('CountdownPlugin.EditCountdownForm',
'Split a slide into two by inserting a slide splitter.'))

View File

@ -0,0 +1,97 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
import logging
from PyQt5.QtWidgets import QDialog
from .editcountdownslidedialog import Ui_CountdownSlideEditDialog
log = logging.getLogger(__name__)
class EditCountdownSlideForm(QDialog, Ui_CountdownSlideEditDialog):
"""
Class documentation goes here.
"""
log.info('Countdown Verse Editor loaded')
def __init__(self, parent=None):
"""
Constructor
"""
super(EditCountdownSlideForm, self).__init__(parent)
self.setupUi(self)
# Connecting signals and slots
self.insert_button.clicked.connect(self.on_insert_button_clicked)
self.split_button.clicked.connect(self.on_split_button_clicked)
def set_text(self, text):
"""
Set the text for slide_text_edit.
:param text: The text (unicode).
"""
self.slide_text_edit.clear()
if text:
self.slide_text_edit.setPlainText(text)
self.slide_text_edit.setFocus()
def get_text(self):
"""
Returns a list with all slides.
"""
return self.slide_text_edit.toPlainText().split('\n[===]\n')
def on_insert_button_clicked(self):
"""
Adds a slide split at the cursor.
"""
self.insert_single_line_text_at_cursor('[===]')
self.slide_text_edit.setFocus()
def on_split_button_clicked(self):
"""
Adds an optional split at cursor.
"""
self.insert_single_line_text_at_cursor('[---]')
self.slide_text_edit.setFocus()
def insert_single_line_text_at_cursor(self, text):
"""
Adds a single line at the cursor position.
:param text: The text to be inserted
"""
full_text = self.slide_text_edit.toPlainText()
position = self.slide_text_edit.textCursor().position()
if position and full_text[position - 1] != '\n':
text = '\n' + text
if position == len(full_text) or full_text[position] != '\n':
text += '\n'
self.slide_text_edit.insertPlainText(text)

View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################

View File

@ -0,0 +1,126 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
The :mod:`~openlp.plugins.countdown.lib.countdowntab` module contains the settings tab
for the Countdown Slides plugin, which is inserted into the configuration dialog.
"""
from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import translate
from openlp.core.common.settings import Settings
from openlp.core.lib.settingstab import SettingsTab
class CountdownTab(SettingsTab):
"""
CountdownTab is the Countdown settings tab in the settings dialog.
"""
def __init__(self, parent, title, visible_title, icon_path):
super(CountdownTab, self).__init__(parent, title, visible_title, icon_path)
def setupUi(self):
self.setObjectName('CountdownTab')
super(CountdownTab, self).setupUi()
self.countdown_mode_group_box = QtWidgets.QGroupBox(self.left_column)
self.countdown_mode_group_box.setObjectName('countdown_mode_group_box')
self.countdown_mode_layout = QtWidgets.QFormLayout(self.countdown_mode_group_box)
self.countdown_mode_layout.setObjectName('countdown_mode_layout')
self.show_countdown_event_name_checkbox = QtWidgets.QCheckBox(self.countdown_mode_group_box)
self.show_countdown_event_name_checkbox.setObjectName('show_countdown_event_name_checkbox')
self.show_countdown_legend_checkbox = QtWidgets.QCheckBox(self.countdown_mode_group_box)
self.show_countdown_legend_checkbox.setObjectName('show_countdown_legend_checkbox')
self.countdown_mode_layout.addRow(self.show_countdown_event_name_checkbox)
self.countdown_mode_layout.addRow(self.show_countdown_legend_checkbox)
self.left_layout.addWidget(self.countdown_mode_group_box)
self.left_layout.addStretch()
self.right_layout.addStretch()
self.show_countdown_event_name_checkbox.stateChanged.connect(self.on_show_countdown_event_name_check_box_changed)
self.show_countdown_legend_checkbox.stateChanged.connect(self.on_show_countdown_legend_check_box_changed)
def retranslateUi(self):
self.countdown_mode_group_box.setTitle(translate('CountdownPlugin.CountdownTab', 'Countdown Options'))
self.show_countdown_event_name_checkbox.setText(translate('CountdownPlugin.CountdownTab',
'Show Countdown event name'))
self.show_countdown_legend_checkbox.setText(translate('CountdownPlugin.CountdownTab',
'Show a legend with the countdon (H:M:S)'))
def on_show_countdown_event_name_check_box_changed(self, check_state):
"""
Toggle the setting for displaying the countdown event name.
:param check_state: The current check box state
"""
self.display_event_name = False
# we have a set value convert to True/False
if check_state == QtCore.Qt.Checked:
self.display_event_name = True
def on_show_countdown_legend_check_box_changed(self, check_state):
"""
Toggle the setting for displaying the countdown legend
:param check_state: The current check box state
"""
self.display_legend = False
# we have a set value convert to True/False
if check_state == QtCore.Qt.Checked:
self.display_legend = True
def load(self):
"""
Load the settings into the dialog
"""
settings = Settings()
settings.beginGroup(self.settings_section)
self.display_event_name = settings.value('display event name')
self.display_legend = settings.value('display legend')
self.show_countdown_event_name_checkbox.setChecked(self.display_event_name)
self.show_countdown_legend_checkbox.setChecked(self.display_legend)
settings.endGroup()
def save(self):
"""
Save the Dialog settings
"""
settings = Settings()
settings.beginGroup(self.settings_section)
settings.setValue('display event name', self.display_event_name)
settings.setValue('display legend', self.display_legend)
settings.endGroup()
if self.tab_visited:
self.settings_form.register_post_process('countdown_config_updated')
self.tab_visited = False

View File

@ -0,0 +1,163 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
The :mod:`countdownxmlhandler` module provides the XML functionality for countdown
slides
The basic XML is of the format::
<?xml version="1.0" encoding="UTF-8"?>
<song version="1.0">
<lyrics language="en">
<verse type="chorus" label="1">
<![CDATA[ ... ]]>
</verse>
</lyrics>
</song>
"""
import logging
import datetime
from xml.dom.minidom import Document
from xml.etree.ElementTree import dump
from lxml import etree, objectify
log = logging.getLogger(__name__)
# TODO: These classes need to be refactored into a single class.
class CountdownXMLBuilder(object):
"""
This class builds the XML used to describe songs.
"""
log.info('CountdownXMLBuilder Loaded')
def __init__(self):
"""
Set up the countdown builder.
"""
# Create the minidom document
self.countdown_xml = Document()
self.new_document()
self.add_lyrics_to_song()
def new_document(self):
"""
Create a new countdown XML document.
"""
# Create the <song> base element
self.song = self.countdown_xml.createElement('song')
self.countdown_xml.appendChild(self.song)
self.song.setAttribute('version', '1.0')
def add_lyrics_to_song(self):
"""
Set up and add a ``<lyrics>`` tag which contains the lyrics of the
countdown item.
"""
# Create the main <lyrics> element
self.lyrics = self.countdown_xml.createElement('lyrics')
self.lyrics.setAttribute('language', 'en')
self.song.appendChild(self.lyrics)
def add_verse_to_lyrics(self, verse_type, number, content):
"""
Add a verse to the ``<lyrics>`` tag.
:param verse_type: A string denoting the type of verse. Possible values are "Chorus", "Verse", "Bridge",
and "Countdown".
:param number: An integer denoting the number of the item, for example: verse 1.
:param content: The actual text of the verse to be stored.
"""
verse = self.countdown_xml.createElement('verse')
verse.setAttribute('type', verse_type)
verse.setAttribute('label', number)
self.lyrics.appendChild(verse)
# add data as a CDATA section to protect the XML from special chars
cds = self.countdown_xml.createCDATASection(content)
verse.appendChild(cds)
def _dump_xml(self):
"""
Debugging aid to dump XML so that we can see what we have.
"""
return self.countdown_xml.toprettyxml(indent=' ')
def extract_xml(self):
"""
Extract our newly created XML countdown.
"""
return self.countdown_xml.toxml('utf-8')
class CountdownXMLParser(object):
"""
A class to read in and parse a countdown's XML.
"""
log.info('CountdownXMLParser Loaded')
def __init__(self, xml):
"""
Set up our countdown XML parser.
:param xml: The XML of the countdown to be parsed.
"""
self.countdown_xml = None
if xml[:5] == '<?xml':
xml = xml[38:]
try:
self.countdown_xml = objectify.fromstring(xml)
except etree.XMLSyntaxError:
log.exception('Invalid xml %s', xml)
def get_time_remaining(self):
"""
Iterates through the verses in the XML and returns a list of verses and their attributes.
"""
"""xml_iter = self.countdown_xml.getiterator()
verse_list = []
for element in xml_iter:
if element.tag == 'verse':
if element.text is None:
element.text = ''
verse_list.append([element.attrib, str(element.text)])
"""
time_remaining = datetime.datetime(2011, 5, 5) - datetime.datetime.now()
return str(time_remaining)
def get_countdown_item_settings(self):
test = 'test data'
return test
def _dump_xml(self):
"""
Debugging aid to dump XML so that we can see what we have.
"""
return dump(self.countdown_xml)

View File

@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
"""
The :mod:`db` module provides the database and schema that is the backend for
the Countdown plugin
"""
from sqlalchemy import Column, Table, types
from sqlalchemy.orm import mapper
from openlp.core.lib.db import BaseModel, init_db
from openlp.core.common.i18n import get_locale_key
class CountdownSlide(BaseModel):
"""
CountdownSlide model
"""
# By default sort the countdowns by its title considering language specific characters.
def __lt__(self, other):
return get_locale_key(self.title) < get_locale_key(other.title)
def __eq__(self, other):
return get_locale_key(self.title) == get_locale_key(other.title)
def __hash__(self):
"""
Return the hash for a countdown slide.
"""
return self.id
def init_schema(url):
"""
Setup the countdown database connection and initialise the database schema
:param url: The database to setup
"""
session, metadata = init_db(url)
countdown_slide_table = Table('countdown_slide', metadata,
Column('id', types.Integer(), primary_key=True),
Column('title', types.Unicode(255), nullable=False),
Column('countdown_type', types.Integer),
Column('countdown_duration', types.Time),
Column('countdown_use_specific_date', types.Unicode(2)),
Column('countdown_specific_date', types.Date),
Column('countdown_use_specific_time', types.Unicode(2)),
Column('countdown_specific_time', types.Time),
Column('interval_large', types.Integer),
Column('interval_small', types.Integer),
Column('finish_action', types.Integer),
Column('theme_name', types.Unicode(128))
)
mapper(CountdownSlide, countdown_slide_table)
metadata.create_all(checkfirst=True)
return session

View File

@ -0,0 +1,317 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2014 Raoul Snyman #
# ountdown copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
import logging
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtWidgets import QDialog
from sqlalchemy.sql import or_, func, and_
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.lib.mediamanageritem import MediaManagerItem
from openlp.core.lib.serviceitem import ItemCapabilities
from openlp.core.lib.plugin import PluginStatus
from openlp.core.lib import ServiceItemContext, check_item_selected
from openlp.plugins.countdown.forms.editcountdownform import EditCountdownForm
from openlp.plugins.countdown.lib.db import CountdownSlide
log = logging.getLogger(__name__)
class CountdownSearch(object):
"""
An enumeration for countdown search methods.
"""
Titles = 1
Themes = 2
class CountdownMediaItem(MediaManagerItem):
"""
This is the countdown media manager item for Countdown Slides.
"""
log.info('Countdown Media Item loaded')
def __init__(self, parent, plugin):
self.icon_path = 'countdown/countdown'
super(CountdownMediaItem, self).__init__(parent, plugin)
def setup_item(self):
"""
Do some additional setup.
"""
self.edit_countdown_form = EditCountdownForm(self, self.main_window, self.plugin.db_manager)
self.single_service_item = False
self.quick_preview_allowed = True
self.has_search = True
# Holds information about whether the edit is remotely triggered and
# which Countdown is required.
self.remote_countdown = -1
def add_end_header_bar(self):
"""
Add the Countdown End Head bar and register events and functions
"""
self.toolbar.addSeparator()
self.add_search_to_toolbar()
# Signals and slots
QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL('cleared()'), self.on_clear_text_button_click)
QtCore.QObject.connect(self.search_text_edit, QtCore.SIGNAL('searchTypeChanged(int)'),
self.on_search_text_button_clicked)
Registry().register_function('countdown_load_list', self.load_list)
Registry().register_function('countdown_preview', self.on_preview_click)
# Registry().register_function('countdown_create_from_service', self.create_from_service_item)
def config_update(self):
"""
Config has been updated so reload values
"""
log.debug('Config loaded')
def retranslateUi(self):
"""
"""
self.search_text_label.setText('%s:' % UiStrings().Search)
self.search_text_button.setText(UiStrings().Search)
def initialise(self):
"""
Initialise the UI so it can provide Searches
"""
self.search_text_edit.set_search_types(
[(CountdownSearch.Titles, ':/songs/song_search_title.png', translate('SongsPlugin.MediaItem', 'Titles'),
translate('SongsPlugin.MediaItem', 'Search Titles...')),
(CountdownSearch.Themes, ':/slides/slide_theme.png', UiStrings().Themes, UiStrings().SearchThemes)])
self.search_text_edit.set_current_search_type(Settings().value('%s/last search type' % self.settings_section))
self.load_list(self.plugin.db_manager.get_all_objects(CountdownSlide, order_by_ref=CountdownSlide.title))
self.config_update()
def load_list(self, countdown_slides, target_group=None):
# Sort out what countdown we want to select after loading the list.
"""
:param countdown_slides:
:param target_group:
"""
self.save_auto_select_id()
self.list_view.clear()
countdown_slides.sort()
for countdown_slide in countdown_slides:
countdown_name = QtGui.QListWidgetItem(countdown_slide.title)
countdown_name.setData(QtCore.Qt.UserRole, countdown_slide.id)
self.list_view.addItem(countdown_name)
# Auto-select the countdown.
if countdown_slide.id == self.auto_select_id:
self.list_view.setCurrentItem(countdown_name)
self.auto_select_id = -1
# Called to redisplay the countdown list screen edith from a search
# or from the exit of the Countdown edit dialog. If remote editing is
# active trigger it and clean up so it will not update again.
def on_new_click(self):
"""
Handle the New item event
"""
self.edit_countdown_form.load_countdown(0)
self.edit_countdown_form.exec_()
self.on_clear_text_button_click()
self.on_selection_change()
def on_remote_edit(self, countdown_id, preview=False):
"""
Called by ServiceManager or SlideController by event passing the countdown Id in the payload along with an
indicator to say which type of display is required.
:param countdown_id: The id of the item to be edited
:param preview: Do we need to update the Preview after the edit. (Default False)
"""
countdown_id = int(countdown_id)
valid = self.plugin.db_manager.get_object(CountdownSlide, countdown_id)
if valid:
self.edit_countdown_form.load_countdown(countdown_id, preview)
if self.edit_countdown_form.exec_() == QDialog.Accepted:
self.remote_triggered = True
self.remote_countdown = countdown_id
self.auto_select_id = -1
self.on_search_text_button_clicked()
item = self.build_service_item(remote=True)
self.remote_triggered = None
self.remote_countdown = 1
if item:
return item
return None
def on_edit_click(self):
"""
Edit a countdown item
"""
if check_item_selected(self.list_view, UiStrings().SelectEdit):
item = self.list_view.currentItem()
item_id = item.data(QtCore.Qt.UserRole)
self.edit_countdown_form.load_countdown(item_id, False)
self.edit_countdown_form.exec_()
self.auto_select_id = -1
self.on_search_text_button_clicked()
def on_delete_click(self):
"""
Remove a countdown item from the list and database
"""
if check_item_selected(self.list_view, UiStrings().SelectDelete):
items = self.list_view.selectedIndexes()
if QtWidgets.QMessageBox.question(self, UiStrings().ConfirmDelete,
translate('CountdownPlugin.MediaItem',
'Are you sure you want to delete the %n selected countdown slide(s)?',
'', QtCore.QCoreApplication.CodecForTr, len(items)),
QtWidgets.QMessageBox.StandardButtons(
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.No:
return
row_list = [item.row() for item in self.list_view.selectedIndexes()]
row_list.sort(reverse=True)
id_list = [(item.data(QtCore.Qt.UserRole)) for item in self.list_view.selectedIndexes()]
for id in id_list:
self.plugin.db_manager.delete_object(CountdownSlide, id)
self.on_search_text_button_clicked()
def on_focus(self):
"""
Set the focus
"""
self.search_text_edit.setFocus()
def generate_slide_data(self, service_item, item=None, xml_version=False,
remote=False, context=ServiceItemContext.Service):
"""
Generate the slide data. Needs to be implemented by the plugin.
:param service_item: To be updated
:param item: The countdown database item to be used
:param xml_version: No used
:param remote: Is this triggered by the Preview Controller or Service Manager.
:param context: Why is this item required to be build (Default Service).
"""
item_id = self._get_id_of_item_to_generate(item, self.remote_countdown)
service_item.add_capability(ItemCapabilities.CanEdit)
service_item.add_capability(ItemCapabilities.CanPreview)
service_item.add_capability(ItemCapabilities.CanLoop)
service_item.add_capability(ItemCapabilities.CanSoftBreak)
service_item.add_capability(ItemCapabilities.OnLoadUpdate)
service_item.add_capability(ItemCapabilities.CanAutoStartForLive)
service_item.add_capability(ItemCapabilities.CanEditTitle)
countdown_slide = self.plugin.db_manager.get_object(CountdownSlide, item_id)
title = countdown_slide.title
service_item.edit_id = item_id
theme = countdown_slide.theme_name
if theme:
service_item.theme = theme
service_item.title = "Countdown until " + title
service_item.processor = 'webkit'
service_item.add_from_text("Countdown until " + title)
return True
def on_search_text_button_clicked(self):
"""
Search the plugin database
"""
# Save the current search type to the configuration.
Settings().setValue('%s/last search type' % self.settings_section, self.search_text_edit.current_search_type())
# Reload the list considering the new search type.
search_type = self.search_text_edit.current_search_type()
search_keywords = '%' + self.whitespace.sub(' ', self.search_text_edit.displayText()) + '%'
if search_type == CountdownSearch.Titles:
log.debug('Titles Search')
search_results = self.plugin.db_manager.get_all_objects(CountdownSlide,
CountdownSlide.title.like(search_keywords),
order_by_ref=CountdownSlide.title)
self.load_list(search_results)
elif search_type == CountdownSearch.Themes:
log.debug('Theme Search')
search_results = self.plugin.db_manager.get_all_objects(CountdownSlide,
CountdownSlide.theme_name.like(search_keywords),
order_by_ref=CountdownSlide.title)
self.load_list(search_results)
self.check_search_result()
def on_search_text_edit_changed(self, text):
"""
If search as type enabled invoke the search on each key press. If the Title is being searched do not start until
2 characters have been entered.
:param text: The search text
"""
search_length = 2
if len(text) > search_length:
self.on_search_text_button_clicked()
elif not text:
self.on_clear_text_button_click()
def service_load(self, item):
"""
Triggered by a countdown item being loaded by the service manager.
:param item: The service Item from the service to load found in the database.
"""
log.debug('service_load')
if self.plugin.status != PluginStatus.Active:
return
countdown = self.plugin.db_manager.get_object_filtered(CountdownSlide, and_(CountdownSlide.title == item.title,
CountdownSlide.theme_name == item.theme,
CountdownSlide.credits ==
item.raw_footer[0][len(item.title) + 1:]))
if countdown:
item.edit_id = countdown.id
return item
else:
if self.add_countdown_from_service:
self.create_from_service_item(item)
def on_clear_text_button_click(self):
"""
Clear the search text.
"""
self.search_text_edit.clear()
self.on_search_text_button_clicked()
def search(self, string, show_error):
"""
Search the database for a given item.
:param string: The search string
:param show_error: The error string to be show.
"""
search = '%' + string.lower() + '%'
search_results = self.plugin.db_manager.get_all_objects(CountdownSlide,
or_(func.lower(CountdownSlide.title).like(search),
func.lower(CountdownSlide.text).like(search)),
order_by_ref=CountdownSlide.title)
return [[countdown.id, countdown.title] for countdown in search_results]

22
resources/countdown.js Normal file
View File

@ -0,0 +1,22 @@
/*
countdown.js v2.3.4 http://countdownjs.org
Copyright (c)2006-2012 Stephen M. McKamey.
Licensed under The MIT License.
*/
var module,countdown=function(r){function v(a,b){var c=a.getTime();a.setUTCMonth(a.getUTCMonth()+b);return Math.round((a.getTime()-c)/864E5)}function t(a){var b=a.getTime(),c=new Date(b);c.setUTCMonth(a.getUTCMonth()+1);return Math.round((c.getTime()-b)/864E5)}function f(a,b){return a+" "+(1===a?p[b]:q[b])}function n(){}function l(a,b,c,g,x,d){0<=a[c]&&(b+=a[c],delete a[c]);b/=x;if(1>=b+1)return 0;if(0<=a[g]){a[g]=+(a[g]+b).toFixed(d);switch(g){case "seconds":if(60!==a.seconds||isNaN(a.minutes))break;
a.minutes++;a.seconds=0;case "minutes":if(60!==a.minutes||isNaN(a.hours))break;a.hours++;a.minutes=0;case "hours":if(24!==a.hours||isNaN(a.days))break;a.days++;a.hours=0;case "days":if(7!==a.days||isNaN(a.weeks))break;a.weeks++;a.days=0;case "weeks":if(a.weeks!==t(a.refMonth)/7||isNaN(a.months))break;a.months++;a.weeks=0;case "months":if(12!==a.months||isNaN(a.years))break;a.years++;a.months=0;case "years":if(10!==a.years||isNaN(a.decades))break;a.decades++;a.years=0;case "decades":if(10!==a.decades||
isNaN(a.centuries))break;a.centuries++;a.decades=0;case "centuries":if(10!==a.centuries||isNaN(a.millennia))break;a.millennia++;a.centuries=0}return 0}return b}function w(a,b,c,g,d,k){a.start=b;a.end=c;a.units=g;a.value=c.getTime()-b.getTime();if(0>a.value){var f=c;c=b;b=f}a.refMonth=new Date(b.getFullYear(),b.getMonth(),15);try{a.millennia=0;a.centuries=0;a.decades=0;a.years=c.getUTCFullYear()-b.getUTCFullYear();a.months=c.getUTCMonth()-b.getUTCMonth();a.weeks=0;a.days=c.getUTCDate()-b.getUTCDate();
a.hours=c.getUTCHours()-b.getUTCHours();a.minutes=c.getUTCMinutes()-b.getUTCMinutes();a.seconds=c.getUTCSeconds()-b.getUTCSeconds();a.milliseconds=c.getUTCMilliseconds()-b.getUTCMilliseconds();var h;0>a.milliseconds?(h=s(-a.milliseconds/1E3),a.seconds-=h,a.milliseconds+=1E3*h):1E3<=a.milliseconds&&(a.seconds+=m(a.milliseconds/1E3),a.milliseconds%=1E3);0>a.seconds?(h=s(-a.seconds/60),a.minutes-=h,a.seconds+=60*h):60<=a.seconds&&(a.minutes+=m(a.seconds/60),a.seconds%=60);0>a.minutes?(h=s(-a.minutes/
60),a.hours-=h,a.minutes+=60*h):60<=a.minutes&&(a.hours+=m(a.minutes/60),a.minutes%=60);0>a.hours?(h=s(-a.hours/24),a.days-=h,a.hours+=24*h):24<=a.hours&&(a.days+=m(a.hours/24),a.hours%=24);for(;0>a.days;)a.months--,a.days+=v(a.refMonth,1);7<=a.days&&(a.weeks+=m(a.days/7),a.days%=7);0>a.months?(h=s(-a.months/12),a.years-=h,a.months+=12*h):12<=a.months&&(a.years+=m(a.months/12),a.months%=12);10<=a.years&&(a.decades+=m(a.years/10),a.years%=10,10<=a.decades&&(a.centuries+=m(a.decades/10),a.decades%=
10,10<=a.centuries&&(a.millennia+=m(a.centuries/10),a.centuries%=10)));b=0;!(g&1024)||b>=d?(a.centuries+=10*a.millennia,delete a.millennia):a.millennia&&b++;!(g&512)||b>=d?(a.decades+=10*a.centuries,delete a.centuries):a.centuries&&b++;!(g&256)||b>=d?(a.years+=10*a.decades,delete a.decades):a.decades&&b++;!(g&128)||b>=d?(a.months+=12*a.years,delete a.years):a.years&&b++;!(g&64)||b>=d?(a.months&&(a.days+=v(a.refMonth,a.months)),delete a.months,7<=a.days&&(a.weeks+=m(a.days/7),a.days%=7)):a.months&&
b++;!(g&32)||b>=d?(a.days+=7*a.weeks,delete a.weeks):a.weeks&&b++;!(g&16)||b>=d?(a.hours+=24*a.days,delete a.days):a.days&&b++;!(g&8)||b>=d?(a.minutes+=60*a.hours,delete a.hours):a.hours&&b++;!(g&4)||b>=d?(a.seconds+=60*a.minutes,delete a.minutes):a.minutes&&b++;!(g&2)||b>=d?(a.milliseconds+=1E3*a.seconds,delete a.seconds):a.seconds&&b++;if(!(g&1)||b>=d){var e=l(a,0,"milliseconds","seconds",1E3,k);if(e&&(e=l(a,e,"seconds","minutes",60,k))&&(e=l(a,e,"minutes","hours",60,k))&&(e=l(a,e,"hours","days",
24,k))&&(e=l(a,e,"days","weeks",7,k))&&(e=l(a,e,"weeks","months",t(a.refMonth)/7,k))){g=e;var n,p=a.refMonth,q=p.getTime(),r=new Date(q);r.setUTCFullYear(p.getUTCFullYear()+1);n=Math.round((r.getTime()-q)/864E5);if(e=l(a,g,"months","years",n/t(a.refMonth),k))if(e=l(a,e,"years","decades",10,k))if(e=l(a,e,"decades","centuries",10,k))if(e=l(a,e,"centuries","millennia",10,k))throw Error("Fractional unit overflow");}}}finally{delete a.refMonth}return a}function d(a,b,c,d,f){var k;c=+c||222;d=0<d?d:NaN;
f=0<f?20>f?Math.round(f):20:0;"function"===typeof a?(k=a,a=null):a instanceof Date||(a=null!==a&&isFinite(a)?new Date(a):null);"function"===typeof b?(k=b,b=null):b instanceof Date||(b=null!==b&&isFinite(b)?new Date(b):null);if(!a&&!b)return new n;if(!k)return w(new n,a||new Date,b||new Date,c,d,f);var l=c&1?1E3/30:c&2?1E3:c&4?6E4:c&8?36E5:c&16?864E5:6048E5,h,e=function(){k(w(new n,a||new Date,b||new Date,c,d,f),h)};e();return h=setInterval(e,l)}var s=Math.ceil,m=Math.floor,p,q,u;n.prototype.toString=
function(){var a=u(this),b=a.length;if(!b)return"";1<b&&(a[b-1]="and "+a[b-1]);return a.join(", ")};n.prototype.toHTML=function(a){a=a||"span";var b=u(this),c=b.length;if(!c)return"";for(var d=0;d<c;d++)b[d]="\x3c"+a+"\x3e"+b[d]+"\x3c/"+a+"\x3e";--c&&(b[c]="and "+b[c]);return b.join(", ")};u=function(a){var b=[],c=a.millennia;c&&b.push(f(c,10));(c=a.centuries)&&b.push(f(c,9));(c=a.decades)&&b.push(f(c,8));(c=a.years)&&b.push(f(c,7));(c=a.months)&&b.push(f(c,6));(c=a.weeks)&&b.push(f(c,5));(c=a.days)&&
b.push(f(c,4));(c=a.hours)&&b.push(f(c,3));(c=a.minutes)&&b.push(f(c,2));(c=a.seconds)&&b.push(f(c,1));(c=a.milliseconds)&&b.push(f(c,0));return b};d.MILLISECONDS=1;d.SECONDS=2;d.MINUTES=4;d.HOURS=8;d.DAYS=16;d.WEEKS=32;d.MONTHS=64;d.YEARS=128;d.DECADES=256;d.CENTURIES=512;d.MILLENNIA=1024;d.DEFAULTS=222;d.ALL=2047;d.setLabels=function(a,b){a=a||[];a.split&&(a=a.split("|"));b=b||[];b.split&&(b=b.split("|"));for(var c=0;10>=c;c++)p[c]=a[c]||p[c],q[c]=b[c]||q[c]};(d.resetLabels=function(){p="millisecond second minute hour day week month year decade century millennium".split(" ");
q="milliseconds seconds minutes hours days weeks months years decades centuries millennia".split(" ")})();r&&r.exports?r.exports=d:"function"===typeof window.define&&window.define.amd&&window.define("countdown",[],function(){return d});return d}(module);
function update_countdown_text(){
show_text(countdown( new Date(2014, 11, 28) ).toString());
timer2 = window.setTimeout(function(){update_countdown_text()}, 100);
}
var timer2 = window.setTimeout(function(){update_countdown_text()}, 100);

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

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

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

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

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

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

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

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

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

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

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff