Phill has proposed merging lp:~phill-ridout/openlp/color_button into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)

For more details, see:
https://code.launchpad.net/~phill-ridout/openlp/color_button/+merge/240383

I realise this probably wont get merged until the final release of 2.2. That 
said could you have a look so I can put it to bed until such time?

Added new ColorButton subclassed from QPushButton to select colours reducing 
code duplication
Added tests for ColorButton
Renamed some methods to take in to account the new signal that ColorButton emits
Fixed some tests for FileDialog

lp:~phill-ridout/openlp/color_button (revision 2443)
[SUCCESS] http://ci.openlp.org/job/Branch-01-Pull/747/
[SUCCESS] http://ci.openlp.org/job/Branch-02-Functional-Tests/685/
[SUCCESS] http://ci.openlp.org/job/Branch-03-Interface-Tests/629/
[SUCCESS] http://ci.openlp.org/job/Branch-04a-Windows_Functional_Tests/568/
[SUCCESS] http://ci.openlp.org/job/Branch-04b-Windows_Interface_Tests/177/
[SUCCESS] http://ci.openlp.org/job/Branch-05a-Code_Analysis/382/
[SUCCESS] http://ci.openlp.org/job/Branch-05b-Test_Coverage/256/
-- 
https://code.launchpad.net/~phill-ridout/openlp/color_button/+merge/240383
Your team OpenLP Core is requested to review the proposed merge of 
lp:~phill-ridout/openlp/color_button into lp:openlp.
=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py	2014-10-06 19:10:03 +0000
+++ openlp/core/lib/__init__.py	2014-11-02 20:23:28 +0000
@@ -318,6 +318,7 @@
         return translate('OpenLP.core.lib', '%s, %s', 'Locale list separator: start') % (string_list[0], merged)
 
 
+from .colorbutton import ColorButton
 from .filedialog import FileDialog
 from .screen import ScreenList
 from .listwidgetwithdnd import ListWidgetWithDnD

=== added file 'openlp/core/lib/colorbutton.py'
--- openlp/core/lib/colorbutton.py	1970-01-01 00:00:00 +0000
+++ openlp/core/lib/colorbutton.py	2014-11-02 20:23:28 +0000
@@ -0,0 +1,89 @@
+# -*- 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                          #
+###############################################################################
+
+"""
+Provide a custom widget based on QPushButton for the selection of colors
+"""
+from PyQt4 import QtCore, QtGui
+
+from openlp.core.common import translate
+
+
+class ColorButton(QtGui.QPushButton):
+    """
+    Subclasses QPushbutton to create a "Color Chooser" button
+    """
+
+    colorChanged = QtCore.pyqtSignal(str)
+
+    def __init__(self, parent=None):
+        """
+        Initialise the ColorButton
+        """
+        super(ColorButton, self).__init__()
+        self.parent = parent
+        self.change_color('#ffffff')
+        self.setToolTip(translate('OpenLP.ColorButton', 'Click to select a color.'))
+        self.clicked.connect(self.on_clicked)
+
+    def change_color(self, color):
+        """
+        Sets the _color variable and the background color.
+
+        :param color:  String representation of a hexidecimal color
+        """
+        self._color = color
+        self.setStyleSheet('background-color: %s' % color)
+
+    @property
+    def color(self):
+        """
+        Property method to return the color variable
+
+        :return:  String representation of a hexidecimal color
+        """
+        return self._color
+
+    @color.setter
+    def color(self, color):
+        """
+        Property setter to change the imstamce color
+
+        :param color:  String representation of a hexidecimal color
+        """
+        self.change_color(color)
+
+    def on_clicked(self):
+        """
+        Handle the PushButton clicked signal, showing the ColorDialog and validating the input
+        """
+        new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self._color), self.parent)
+        if new_color.isValid() and self._color != new_color.name():
+            self.change_color(new_color.name())
+            self.colorChanged.emit(new_color.name())

=== modified file 'openlp/core/ui/advancedtab.py'
--- openlp/core/ui/advancedtab.py	2014-04-20 12:06:02 +0000
+++ openlp/core/ui/advancedtab.py	2014-11-02 20:23:28 +0000
@@ -37,7 +37,7 @@
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.common import AppLocation, Settings, SlideLimits, UiStrings, translate
-from openlp.core.lib import SettingsTab, build_icon
+from openlp.core.lib import ColorButton, SettingsTab, build_icon
 from openlp.core.utils import format_time, get_images_filter
 
 log = logging.getLogger(__name__)
@@ -181,7 +181,7 @@
         self.default_image_layout.setObjectName('default_image_layout')
         self.default_color_label = QtGui.QLabel(self.default_image_group_box)
         self.default_color_label.setObjectName('default_color_label')
-        self.default_color_button = QtGui.QPushButton(self.default_image_group_box)
+        self.default_color_button = ColorButton(self.default_image_group_box)
         self.default_color_button.setObjectName('default_color_button')
         self.default_image_layout.addRow(self.default_color_label, self.default_color_button)
         self.default_file_label = QtGui.QLabel(self.default_image_group_box)
@@ -247,7 +247,7 @@
         self.service_name_time.timeChanged.connect(self.update_service_name_example)
         self.service_name_edit.textChanged.connect(self.update_service_name_example)
         self.service_name_revert_button.clicked.connect(self.on_service_name_revert_button_clicked)
-        self.default_color_button.clicked.connect(self.on_default_color_button_clicked)
+        self.default_color_button.colorChanged.connect(self.on_background_color_changed)
         self.default_browse_button.clicked.connect(self.on_default_browse_button_clicked)
         self.default_revert_button.clicked.connect(self.on_default_revert_button_clicked)
         self.alternate_rows_check_box.toggled.connect(self.on_alternate_rows_check_box_toggled)
@@ -299,7 +299,6 @@
         self.hide_mouse_check_box.setText(translate('OpenLP.AdvancedTab', 'Hide mouse cursor when over display window'))
         self.default_image_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Default Image'))
         self.default_color_label.setText(translate('OpenLP.AdvancedTab', 'Background color:'))
-        self.default_color_button.setToolTip(translate('OpenLP.AdvancedTab', 'Click to select a color.'))
         self.default_file_label.setText(translate('OpenLP.AdvancedTab', 'Image file:'))
         self.default_browse_button.setToolTip(translate('OpenLP.AdvancedTab', 'Browse for an image file to display.'))
         self.default_revert_button.setToolTip(translate('OpenLP.AdvancedTab', 'Revert to the default OpenLP logo.'))
@@ -395,7 +394,7 @@
             self.current_data_path = AppLocation.get_data_path()
             log.warning('User requested data path set to default %s' % self.current_data_path)
         self.data_directory_label.setText(os.path.abspath(self.current_data_path))
-        self.default_color_button.setStyleSheet('background-color: %s' % self.default_color)
+        self.default_color_button.color = self.default_color
         # Don't allow data directory move if running portable.
         if settings.value('advanced/is portable'):
             self.data_directory_group_box.hide()
@@ -498,14 +497,11 @@
         self.service_name_edit.setText(UiStrings().DefaultServiceName)
         self.service_name_edit.setFocus()
 
-    def on_default_color_button_clicked(self):
+    def on_background_color_changed(self, color):
         """
         Select the background colour of the default display screen.
         """
-        new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.default_color), self)
-        if new_color.isValid():
-            self.default_color = new_color.name()
-            self.default_color_button.setStyleSheet('background-color: %s' % self.default_color)
+        self.default_color = color
 
     def on_default_browse_button_clicked(self):
         """

=== modified file 'openlp/core/ui/media/playertab.py'
--- openlp/core/ui/media/playertab.py	2014-03-17 19:05:55 +0000
+++ openlp/core/ui/media/playertab.py	2014-11-02 20:23:28 +0000
@@ -32,7 +32,7 @@
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.common import Registry, Settings, UiStrings, translate
-from openlp.core.lib import SettingsTab
+from openlp.core.lib import ColorButton, SettingsTab
 from openlp.core.lib.ui import create_button
 from openlp.core.ui.media import get_media_players, set_media_players
 
@@ -76,7 +76,7 @@
         self.background_color_label = QtGui.QLabel(self.background_color_group_box)
         self.background_color_label.setObjectName('background_color_label')
         self.color_layout.addWidget(self.background_color_label)
-        self.background_color_button = QtGui.QPushButton(self.background_color_group_box)
+        self.background_color_button = ColorButton(self.background_color_group_box)
         self.background_color_button.setObjectName('background_color_button')
         self.color_layout.addWidget(self.background_color_button)
         self.form_layout.addRow(self.color_layout)
@@ -124,7 +124,7 @@
         self.left_layout.addStretch()
         self.right_layout.addStretch()
         # Signals and slots
-        self.background_color_button.clicked.connect(self.on_background_color_button_clicked)
+        self.background_color_button.colorChanged.connect(self.on_background_color_changed)
 
     def retranslateUi(self):
         """
@@ -138,14 +138,11 @@
                                        'Visible background for videos with aspect ratio different to screen.'))
         self.retranslate_players()
 
-    def on_background_color_button_clicked(self):
+    def on_background_color_changed(self, color):
         """
         Set the background color
         """
-        new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.background_color), self)
-        if new_color.isValid():
-            self.background_color = new_color.name()
-            self.background_color_button.setStyleSheet('background-color: %s' % self.background_color)
+        self.background_color = color
 
     def on_player_check_box_changed(self, check_state):
         """
@@ -212,7 +209,7 @@
         self.background_color = settings.value('background color')
         self.initial_color = self.background_color
         settings.endGroup()
-        self.background_color_button.setStyleSheet('background-color: %s' % self.background_color)
+        self.background_color_button.color = self.background_color
 
     def save(self):
         """

=== modified file 'openlp/core/ui/themeform.py'
--- openlp/core/ui/themeform.py	2014-09-04 20:25:23 +0000
+++ openlp/core/ui/themeform.py	2014-11-02 20:23:28 +0000
@@ -65,18 +65,18 @@
         self.theme_layout_form = ThemeLayoutForm(self)
         self.background_combo_box.currentIndexChanged.connect(self.on_background_combo_box_current_index_changed)
         self.gradient_combo_box.currentIndexChanged.connect(self.on_gradient_combo_box_current_index_changed)
-        self.color_button.clicked.connect(self.on_color_button_clicked)
-        self.image_color_button.clicked.connect(self.on_image_color_button_clicked)
-        self.gradient_start_button.clicked.connect(self.on_gradient_start_button_clicked)
-        self.gradient_end_button.clicked.connect(self.on_gradient_end_button_clicked)
+        self.color_button.colorChanged.connect(self.on_color_changed)
+        self.image_color_button.colorChanged.connect(self.on_image_color_changed)
+        self.gradient_start_button.colorChanged.connect(self.on_gradient_start_button_changed)
+        self.gradient_end_button.colorChanged.connect(self.on_gradient_end_button_changed)
         self.image_browse_button.clicked.connect(self.on_image_browse_button_clicked)
         self.image_file_edit.editingFinished.connect(self.on_image_file_edit_editing_finished)
-        self.main_color_button.clicked.connect(self.on_main_color_button_clicked)
-        self.outline_color_button.clicked.connect(self.on_outline_color_button_clicked)
-        self.shadow_color_button.clicked.connect(self.on_shadow_color_button_clicked)
+        self.main_color_button.colorChanged.connect(self.on_main_color_changed)
+        self.outline_color_button.colorChanged.connect(self.on_outline_color_changed)
+        self.shadow_color_button.colorChanged.connect(self.on_shadow_color_changed)
         self.outline_check_box.stateChanged.connect(self.on_outline_check_check_box_state_changed)
         self.shadow_check_box.stateChanged.connect(self.on_shadow_check_check_box_state_changed)
-        self.footer_color_button.clicked.connect(self.on_footer_color_button_clicked)
+        self.footer_color_button.colorChanged.connect(self.on_footer_color_changed)
         self.customButtonClicked.connect(self.on_custom_1_button_clicked)
         self.main_position_check_box.stateChanged.connect(self.on_main_position_check_box_state_changed)
         self.footer_position_check_box.stateChanged.connect(self.on_footer_position_check_box_state_changed)
@@ -295,14 +295,14 @@
         Handle the display and state of the Background page.
         """
         if self.theme.background_type == BackgroundType.to_string(BackgroundType.Solid):
-            self.color_button.setStyleSheet('background-color: %s' % self.theme.background_color)
+            self.color_button.color = self.theme.background_color
             self.setField('background_type', 0)
         elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Gradient):
-            self.gradient_start_button.setStyleSheet('background-color: %s' % self.theme.background_start_color)
-            self.gradient_end_button.setStyleSheet('background-color: %s' % self.theme.background_end_color)
+            self.gradient_start_button.color = self.theme.background_start_color
+            self.gradient_end_button.color = self.theme.background_end_color
             self.setField('background_type', 1)
         elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Image):
-            self.image_color_button.setStyleSheet('background-color: %s' % self.theme.background_border_color)
+            self.image_color_button.color = self.theme.background_border_color
             self.image_file_edit.setText(self.theme.background_filename)
             self.setField('background_type', 2)
         elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Transparent):
@@ -323,14 +323,14 @@
         Handle the display and state of the Main Area page.
         """
         self.main_font_combo_box.setCurrentFont(QtGui.QFont(self.theme.font_main_name))
-        self.main_color_button.setStyleSheet('background-color: %s' % self.theme.font_main_color)
+        self.main_color_button.color = self.theme.font_main_color
         self.setField('main_size_spin_box', self.theme.font_main_size)
         self.setField('line_spacing_spin_box', self.theme.font_main_line_adjustment)
         self.setField('outline_check_box', self.theme.font_main_outline)
-        self.outline_color_button.setStyleSheet('background-color: %s' % self.theme.font_main_outline_color)
+        self.outline_color_button.color = self.theme.font_main_outline_color
         self.setField('outline_size_spin_box', self.theme.font_main_outline_size)
         self.setField('shadow_check_box', self.theme.font_main_shadow)
-        self.shadow_color_button.setStyleSheet('background-color: %s' % self.theme.font_main_shadow_color)
+        self.shadow_color_button.color = self.theme.font_main_shadow_color
         self.setField('shadow_size_spin_box', self.theme.font_main_shadow_size)
         self.setField('main_bold_check_box', self.theme.font_main_bold)
         self.setField('main_italics_check_box', self.theme.font_main_italics)
@@ -340,7 +340,7 @@
         Handle the display and state of the Footer Area page.
         """
         self.footer_font_combo_box.setCurrentFont(QtGui.QFont(self.theme.font_footer_name))
-        self.footer_color_button.setStyleSheet('background-color: %s' % self.theme.font_footer_color)
+        self.footer_color_button.color = self.theme.font_footer_color
         self.setField('footer_size_spin_box', self.theme.font_footer_size)
 
     def set_position_page_values(self):
@@ -399,33 +399,29 @@
             self.theme.background_direction = BackgroundGradientType.to_string(index)
             self.set_background_page_values()
 
-    def on_color_button_clicked(self):
-        """
-        Background / Gradient 1 _color button pushed.
-        """
-        self.theme.background_color = self._color_button(self.theme.background_color)
-        self.set_background_page_values()
-
-    def on_image_color_button_clicked(self):
-        """
-        Background / Gradient 1 _color button pushed.
-        """
-        self.theme.background_border_color = self._color_button(self.theme.background_border_color)
-        self.set_background_page_values()
-
-    def on_gradient_start_button_clicked(self):
-        """
-        Gradient 2 _color button pushed.
-        """
-        self.theme.background_start_color = self._color_button(self.theme.background_start_color)
-        self.set_background_page_values()
-
-    def on_gradient_end_button_clicked(self):
-        """
-        Gradient 2 _color button pushed.
-        """
-        self.theme.background_end_color = self._color_button(self.theme.background_end_color)
-        self.set_background_page_values()
+    def on_color_changed(self, color):
+        """
+        Background / Gradient 1 _color button pushed.
+        """
+        self.theme.background_color = color
+
+    def on_image_color_changed(self, color):
+        """
+        Background / Gradient 1 _color button pushed.
+        """
+        self.theme.background_border_color = color
+
+    def on_gradient_start_button_changed(self, color):
+        """
+        Gradient 2 _color button pushed.
+        """
+        self.theme.background_start_color = color
+
+    def on_gradient_end_button_changed(self, color):
+        """
+        Gradient 2 _color button pushed.
+        """
+        self.theme.background_end_color = color
 
     def on_image_browse_button_clicked(self):
         """
@@ -445,33 +441,29 @@
         """
         self.theme.background_filename = str(self.image_file_edit.text())
 
-    def on_main_color_button_clicked(self):
+    def on_main_color_changed(self, color):
         """
         Set the main colour value
         """
-        self.theme.font_main_color = self._color_button(self.theme.font_main_color)
-        self.set_main_area_page_values()
+        self.theme.font_main_color = color
 
-    def on_outline_color_button_clicked(self):
+    def on_outline_color_changed(self, color):
         """
         Set the outline colour value
         """
-        self.theme.font_main_outline_color = self._color_button(self.theme.font_main_outline_color)
-        self.set_main_area_page_values()
+        self.theme.font_main_outline_color = color
 
-    def on_shadow_color_button_clicked(self):
+    def on_shadow_color_changed(self, color):
         """
         Set the shadow colour value
         """
-        self.theme.font_main_shadow_color = self._color_button(self.theme.font_main_shadow_color)
-        self.set_main_area_page_values()
+        self.theme.font_main_shadow_color = color
 
-    def on_footer_color_button_clicked(self):
+    def on_footer_color_changed(self, color):
         """
         Set the footer colour value
         """
-        self.theme.font_footer_color = self._color_button(self.theme.font_footer_color)
-        self.set_footer_area_page_values()
+        self.theme.font_footer_color = color
 
     def update_theme(self):
         """
@@ -532,12 +524,3 @@
             return
         self.theme_manager.save_theme(self.theme, save_from, save_to)
         return QtGui.QDialog.accept(self)
-
-    def _color_button(self, field):
-        """
-        Handle _color buttons
-        """
-        new_color = QtGui.QColorDialog.getColor(QtGui.QColor(field), self)
-        if new_color.isValid():
-            field = new_color.name()
-        return field

=== modified file 'openlp/core/ui/themewizard.py'
--- openlp/core/ui/themewizard.py	2014-10-08 19:42:30 +0000
+++ openlp/core/ui/themewizard.py	2014-11-02 20:23:28 +0000
@@ -32,7 +32,7 @@
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.common import UiStrings, translate, is_macosx
-from openlp.core.lib import build_icon
+from openlp.core.lib import build_icon, ColorButton
 from openlp.core.lib.theme import HorizontalType, BackgroundType, BackgroundGradientType
 from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets
 
@@ -82,7 +82,7 @@
         self.color_layout.setObjectName('color_layout')
         self.color_label = QtGui.QLabel(self.color_widget)
         self.color_label.setObjectName('color_label')
-        self.color_button = QtGui.QPushButton(self.color_widget)
+        self.color_button = ColorButton(self.color_widget)
         self.color_button.setObjectName('color_button')
         self.color_layout.addRow(self.color_label, self.color_button)
         self.color_layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
@@ -94,12 +94,12 @@
         self.gradient_layout.setObjectName('gradient_layout')
         self.gradient_start_label = QtGui.QLabel(self.gradient_widget)
         self.gradient_start_label.setObjectName('gradient_start_label')
-        self.gradient_start_button = QtGui.QPushButton(self.gradient_widget)
+        self.gradient_start_button = ColorButton(self.gradient_widget)
         self.gradient_start_button.setObjectName('gradient_start_button')
         self.gradient_layout.addRow(self.gradient_start_label, self.gradient_start_button)
         self.gradient_end_label = QtGui.QLabel(self.gradient_widget)
         self.gradient_end_label.setObjectName('gradient_end_label')
-        self.gradient_end_button = QtGui.QPushButton(self.gradient_widget)
+        self.gradient_end_button = ColorButton(self.gradient_widget)
         self.gradient_end_button.setObjectName('gradient_end_button')
         self.gradient_layout.addRow(self.gradient_end_label, self.gradient_end_button)
         self.gradient_type_label = QtGui.QLabel(self.gradient_widget)
@@ -117,7 +117,7 @@
         self.image_layout.setObjectName('image_layout')
         self.image_color_label = QtGui.QLabel(self.color_widget)
         self.image_color_label.setObjectName('image_color_label')
-        self.image_color_button = QtGui.QPushButton(self.color_widget)
+        self.image_color_button = ColorButton(self.color_widget)
         self.image_color_button.setObjectName('image_color_button')
         self.image_layout.addRow(self.image_color_label, self.image_color_button)
         self.image_label = QtGui.QLabel(self.image_widget)
@@ -156,7 +156,7 @@
         self.main_color_label.setObjectName('main_color_label')
         self.main_properties_layout = QtGui.QHBoxLayout()
         self.main_properties_layout.setObjectName('main_properties_layout')
-        self.main_color_button = QtGui.QPushButton(self.main_area_page)
+        self.main_color_button = ColorButton(self.main_area_page)
         self.main_color_button.setObjectName('main_color_button')
         self.main_properties_layout.addWidget(self.main_color_button)
         self.main_properties_layout.addSpacing(20)
@@ -192,7 +192,7 @@
         self.outline_check_box.setObjectName('outline_check_box')
         self.outline_layout = QtGui.QHBoxLayout()
         self.outline_layout.setObjectName('outline_layout')
-        self.outline_color_button = QtGui.QPushButton(self.main_area_page)
+        self.outline_color_button = ColorButton(self.main_area_page)
         self.outline_color_button.setEnabled(False)
         self.outline_color_button.setObjectName('Outline_color_button')
         self.outline_layout.addWidget(self.outline_color_button)
@@ -209,7 +209,7 @@
         self.shadow_check_box.setObjectName('shadow_check_box')
         self.shadow_layout = QtGui.QHBoxLayout()
         self.shadow_layout.setObjectName('shadow_layout')
-        self.shadow_color_button = QtGui.QPushButton(self.main_area_page)
+        self.shadow_color_button = ColorButton(self.main_area_page)
         self.shadow_color_button.setEnabled(False)
         self.shadow_color_button.setObjectName('shadow_color_button')
         self.shadow_layout.addWidget(self.shadow_color_button)
@@ -235,7 +235,7 @@
         self.footer_area_layout.addRow(self.footer_font_label, self.footer_font_combo_box)
         self.footer_color_label = QtGui.QLabel(self.footer_area_page)
         self.footer_color_label.setObjectName('footer_color_label')
-        self.footer_color_button = QtGui.QPushButton(self.footer_area_page)
+        self.footer_color_button = ColorButton(self.footer_area_page)
         self.footer_color_button.setObjectName('footer_color_button')
         self.footer_area_layout.addRow(self.footer_color_label, self.footer_color_button)
         self.footer_size_label = QtGui.QLabel(self.footer_area_page)

=== modified file 'openlp/plugins/alerts/lib/alertstab.py'
--- openlp/plugins/alerts/lib/alertstab.py	2014-01-01 09:33:07 +0000
+++ openlp/plugins/alerts/lib/alertstab.py	2014-11-02 20:23:28 +0000
@@ -30,7 +30,7 @@
 from PyQt4 import QtGui
 
 from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import SettingsTab
+from openlp.core.lib import ColorButton, SettingsTab
 from openlp.core.lib.ui import create_valign_selection_widgets
 
 
@@ -57,14 +57,14 @@
         self.font_color_label.setObjectName('font_color_label')
         self.color_layout = QtGui.QHBoxLayout()
         self.color_layout.setObjectName('color_layout')
-        self.font_color_button = QtGui.QPushButton(self.font_group_box)
+        self.font_color_button = ColorButton(self.font_group_box)
         self.font_color_button.setObjectName('font_color_button')
         self.color_layout.addWidget(self.font_color_button)
         self.color_layout.addSpacing(20)
         self.background_color_label = QtGui.QLabel(self.font_group_box)
         self.background_color_label.setObjectName('background_color_label')
         self.color_layout.addWidget(self.background_color_label)
-        self.background_color_button = QtGui.QPushButton(self.font_group_box)
+        self.background_color_button = ColorButton(self.font_group_box)
         self.background_color_button.setObjectName('background_color_button')
         self.color_layout.addWidget(self.background_color_button)
         self.font_layout.addRow(self.font_color_label, self.color_layout)
@@ -95,8 +95,8 @@
         self.right_layout.addWidget(self.preview_group_box)
         self.right_layout.addStretch()
         # Signals and slots
-        self.background_color_button.clicked.connect(self.on_background_color_button_clicked)
-        self.font_color_button.clicked.connect(self.on_font_color_button_clicked)
+        self.background_color_button.colorChanged.connect(self.on_background_color_changed)
+        self.font_color_button.colorChanged.connect(self.on_font_color_changed)
         self.font_combo_box.activated.connect(self.on_font_combo_box_clicked)
         self.timeout_spin_box.valueChanged.connect(self.on_timeout_spin_box_changed)
         self.font_size_spin_box.valueChanged.connect(self.on_font_size_spin_box_changed)
@@ -113,15 +113,12 @@
         self.preview_group_box.setTitle(UiStrings().Preview)
         self.font_preview.setText(UiStrings().OLPV2x)
 
-    def on_background_color_button_clicked(self):
+    def on_background_color_changed(self, color):
         """
         The background color has been changed.
         """
-        new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.background_color), self)
-        if new_color.isValid():
-            self.background_color = new_color.name()
-            self.background_color_button.setStyleSheet('background-color: %s' % self.background_color)
-            self.update_display()
+        self.background_color = color
+        self.update_display()
 
     def on_font_combo_box_clicked(self):
         """
@@ -129,15 +126,12 @@
         """
         self.update_display()
 
-    def on_font_color_button_clicked(self):
+    def on_font_color_changed(self, color):
         """
         The Font Color button has clicked.
         """
-        new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.font_color), self)
-        if new_color.isValid():
-            self.font_color = new_color.name()
-            self.font_color_button.setStyleSheet('background-color: %s' % self.font_color)
-            self.update_display()
+        self.font_color = color
+        self.update_display()
 
     def on_timeout_spin_box_changed(self):
         """
@@ -169,8 +163,8 @@
         settings.endGroup()
         self.font_size_spin_box.setValue(self.font_size)
         self.timeout_spin_box.setValue(self.timeout)
-        self.font_color_button.setStyleSheet('background-color: %s' % self.font_color)
-        self.background_color_button.setStyleSheet('background-color: %s' % self.background_color)
+        self.font_color_button.color = self.font_color
+        self.background_color_button.color = self.background_color
         self.vertical_combo_box.setCurrentIndex(self.location)
         font = QtGui.QFont()
         font.setFamily(self.font_face)

=== modified file 'openlp/plugins/images/lib/imagetab.py'
--- openlp/plugins/images/lib/imagetab.py	2013-12-24 08:56:50 +0000
+++ openlp/plugins/images/lib/imagetab.py	2014-11-02 20:23:28 +0000
@@ -30,7 +30,7 @@
 from PyQt4 import QtGui
 
 from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import SettingsTab
+from openlp.core.lib import ColorButton, SettingsTab
 
 
 class ImageTab(SettingsTab):
@@ -51,7 +51,7 @@
         self.background_color_label = QtGui.QLabel(self.background_color_group_box)
         self.background_color_label.setObjectName('background_color_label')
         self.color_layout.addWidget(self.background_color_label)
-        self.background_color_button = QtGui.QPushButton(self.background_color_group_box)
+        self.background_color_button = ColorButton(self.background_color_group_box)
         self.background_color_button.setObjectName('background_color_button')
         self.color_layout.addWidget(self.background_color_button)
         self.form_layout.addRow(self.color_layout)
@@ -64,7 +64,7 @@
         self.right_column.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred)
         self.right_layout.addStretch()
         # Signals and slots
-        self.background_color_button.clicked.connect(self.on_background_color_button_clicked)
+        self.background_color_button.colorChanged.connect(self.on_background_color_changed)
 
     def retranslateUi(self):
         self.background_color_group_box.setTitle(UiStrings().BackgroundColor)
@@ -72,11 +72,8 @@
         self.information_label.setText(
             translate('ImagesPlugin.ImageTab', 'Visible background for images with aspect ratio different to screen.'))
 
-    def on_background_color_button_clicked(self):
-        new_color = QtGui.QColorDialog.getColor(QtGui.QColor(self.background_color), self)
-        if new_color.isValid():
-            self.background_color = new_color.name()
-            self.background_color_button.setStyleSheet('background-color: %s' % self.background_color)
+    def on_background_color_changed(self, color):
+        self.background_color = color
 
     def load(self):
         settings = Settings()
@@ -84,7 +81,7 @@
         self.background_color = settings.value('background color')
         self.initial_color = self.background_color
         settings.endGroup()
-        self.background_color_button.setStyleSheet('background-color: %s' % self.background_color)
+        self.background_color_button.color = self.background_color
 
     def save(self):
         settings = Settings()

=== added file 'tests/functional/openlp_core_lib/test_color_button.py'
--- tests/functional/openlp_core_lib/test_color_button.py	1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_lib/test_color_button.py	2014-11-02 20:23:28 +0000
@@ -0,0 +1,206 @@
+# -*- 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 module contains tests for the openlp.core.lib.filedialog module
+"""
+from unittest import TestCase
+
+from openlp.core.lib.colorbutton import ColorButton
+from tests.functional import MagicMock, call, patch
+
+
+class TestColorDialog(TestCase):
+    """
+    Test the :class:`~openlp.core.lib.colorbutton.ColorButton` class
+    """
+    def setUp(self):
+        self.change_color_patcher = patch('openlp.core.lib.colorbutton.ColorButton.change_color')
+        self.clicked_patcher = patch('openlp.core.lib.colorbutton.ColorButton.clicked')
+        self.color_changed_patcher = patch('openlp.core.lib.colorbutton.ColorButton.colorChanged')
+        self.qt_gui_patcher = patch('openlp.core.lib.colorbutton.QtGui')
+        self.translate_patcher = patch('openlp.core.lib.colorbutton.translate', **{'return_value': 'Tool Tip Text'})
+        self.addCleanup(self.change_color_patcher.stop)
+        self.addCleanup(self.clicked_patcher.stop)
+        self.addCleanup(self.color_changed_patcher.stop)
+        self.addCleanup(self.qt_gui_patcher.stop)
+        self.addCleanup(self.translate_patcher.stop)
+        self.mocked_change_color = self.change_color_patcher.start()
+        self.mocked_clicked = self.clicked_patcher.start()
+        self.mocked_color_changed = self.color_changed_patcher.start()
+        self.mocked_qt_gui = self.qt_gui_patcher.start()
+        self.mocked_translate = self.translate_patcher.start()
+
+    def constructor_test(self):
+        """
+        Test that constructing a ColorButton object works correctly
+        """
+
+        # GIVEN: The ColorButton class, a mocked change_color, setToolTip methods and clicked signal
+        with patch('openlp.core.lib.colorbutton.ColorButton.setToolTip') as mocked_set_tool_tip:
+
+            # WHEN: The ColorButton object is instantiated
+            widget = ColorButton()
+
+            # THEN: The widget __init__ method should have the correct properties and methods called
+            self.assertEqual(widget.parent, None,
+                             'The parent should be the same as the one that the class was instianted with')
+            self.mocked_change_color.assert_called_once_with('#ffffff')
+            mocked_set_tool_tip.assert_called_once_with('Tool Tip Text')
+            self.mocked_clicked.connect.assert_called_once_with(widget.on_clicked)
+
+    def change_color_test(self):
+        """
+        Test that change_color sets the new color and the stylesheet
+        """
+        self.change_color_patcher.stop()
+
+        # GIVEN: An instance of the ColorButton object, and a mocked out setStyleSheet
+        with patch('openlp.core.lib.colorbutton.ColorButton.setStyleSheet') as mocked_set_style_sheet:
+            widget = ColorButton()
+
+            # WHEN: Changing the color
+            widget.change_color('#000000')
+
+            # THEN: The _color attribute should be set to #000000 and setStyleSheet should have been called twice
+            self.assertEqual(widget._color, '#000000', '_color should have been set to #000000')
+            mocked_set_style_sheet.assert_has_calls(
+                [call('background-color: #ffffff'), call('background-color: #000000')])
+
+        self.mocked_change_color = self.change_color_patcher.start()
+
+    def color_test(self):
+        """
+        Test that the color property method returns the set color
+        """
+
+        # GIVEN: An instance of ColorButton, with a set _color attribute
+        widget = ColorButton()
+        widget._color = '#000000'
+
+        # WHEN: Accesing the color property
+        value = widget.color
+
+        # THEN: The value set in _color should be returned
+        self.assertEqual(value, '#000000', 'The value returned should be equal to the one we set')
+
+    def color_test(self):
+        """
+        Test that the color property method returns the set color
+        """
+
+        # GIVEN: An instance of ColorButton, with a set _color attribute
+        widget = ColorButton()
+        widget._color = '#000000'
+
+        # WHEN: Accesing the color property
+        value = widget.color
+
+        # THEN: The value set in _color should be returned
+        self.assertEqual(value, '#000000', 'The value returned should be equal to the one we set')
+
+    def color_setter_test(self):
+        """
+        Test that the color property setter method sets the color
+        """
+
+        # GIVEN: An instance of ColorButton, with a mocked __init__
+        with patch('openlp.core.lib.colorbutton.ColorButton.__init__', **{'return_value': None}):
+            widget = ColorButton()
+
+            # WHEN: Setting the color property
+            widget.color = '#000000'
+
+            # THEN: Then change_color should have been called with the value we set
+            self.mocked_change_color.assert_called_once_with('#000000')
+
+    def on_clicked_invalid_color_test(self):
+        """
+        Test the on_click method when an invalid color has been supplied
+        """
+
+        # GIVEN: An instance of ColorButton, and a set _color attribute
+        widget = ColorButton()
+        self.mocked_change_color.reset_mock()
+        self.mocked_color_changed.reset_mock()
+        widget._color = '#000000'
+
+        # WHEN: The on_clicked method is called, and the color is invalid
+        self.mocked_qt_gui.QColorDialog.getColor.return_value = MagicMock(**{'isValid.return_value': False})
+        widget.on_clicked()
+
+        # THEN: change_color should not have been called and the colorChanged signal should not have been emitted
+        self.assertEqual(
+            self.mocked_change_color.call_count, 0, 'change_color should not have been called with an invalid color')
+        self.assertEqual(
+            self.mocked_color_changed.emit.call_count, 0,
+            'colorChange signal should not have been emitted with an invalid color')
+
+    def on_clicked_same_color_test(self):
+        """
+        Test the on_click method when a new color has not been chosen
+        """
+
+        # GIVEN: An instance of ColorButton, and a set _color attribute
+        widget = ColorButton()
+        self.mocked_change_color.reset_mock()
+        self.mocked_color_changed.reset_mock()
+        widget._color = '#000000'
+
+        # WHEN: The on_clicked method is called, and the color is valid, but the same as the existing color
+        self.mocked_qt_gui.QColorDialog.getColor.return_value = MagicMock(
+            **{'isValid.return_value': True, 'name.return_value': '#000000'})
+        widget.on_clicked()
+
+        # THEN: change_color should not have been called and the colorChanged signal should not have been emitted
+        self.assertEqual(
+            self.mocked_change_color.call_count, 0,
+            'change_color should not have been called when the color has not changed')
+        self.assertEqual(
+            self.mocked_color_changed.emit.call_count, 0,
+            'colorChange signal should not have been emitted when the color has not changed')
+
+    def on_clicked_new_color_test(self):
+        """
+        Test the on_click method when a new color has been chosen and is valid
+        """
+
+        # GIVEN: An instance of ColorButton, and a set _color attribute
+        widget = ColorButton()
+        self.mocked_change_color.reset_mock()
+        self.mocked_color_changed.reset_mock()
+        widget._color = '#000000'
+
+        # WHEN: The on_clicked method is called, and the color is valid, and different to the existing color
+        self.mocked_qt_gui.QColorDialog.getColor.return_value = MagicMock(
+            **{'isValid.return_value': True, 'name.return_value': '#ffffff'})
+        widget.on_clicked()
+
+        # THEN: change_color should have been called and the colorChanged signal should have been emitted
+        self.mocked_change_color.assert_call_once_with('#ffffff')
+        self.mocked_color_changed.emit.assert_called_once_with('#ffffff')

=== modified file 'tests/functional/openlp_core_lib/test_file_dialog.py'
--- tests/functional/openlp_core_lib/test_file_dialog.py	2014-07-20 20:00:06 +0000
+++ tests/functional/openlp_core_lib/test_file_dialog.py	2014-11-02 20:23:28 +0000
@@ -31,7 +31,7 @@
             Test that FileDialog.getOpenFileNames() returns and empty QStringList when QFileDialog is canceled
             (returns an empty QStringList)
         """
-        self.mocked_os.reset()
+        self.mocked_os.reset_mock()
 
         # GIVEN: An empty QStringList as a return value from QFileDialog.getOpenFileNames
         self.mocked_qt_gui.QFileDialog.getOpenFileNames.return_value = []
@@ -50,8 +50,8 @@
             Test that FileDialog.getOpenFileNames handles a list of files properly when QFileList.getOpenFileNames
             returns a good file name, a url encoded file name and a non-existing file
         """
-        self.mocked_os.rest()
-        self.mocked_qt_gui.reset()
+        self.mocked_os.rest_mock()
+        self.mocked_qt_gui.reset_mock()
 
         # GIVEN: A List of known values as a return value from QFileDialog.getOpenFileNames and a list of valid file
         # names.
@@ -59,6 +59,8 @@
             '/Valid File', '/url%20encoded%20file%20%231', '/non-existing']
         self.mocked_os.path.exists.side_effect = lambda file_name: file_name in [
             '/Valid File', '/url encoded file #1']
+        self.mocked_ui_strings().FileNotFound = 'File Not Found'
+        self.mocked_ui_strings().FileNotFoundMessage = 'File %s not found.\nPlease try selecting it individually.'
 
         # WHEN: FileDialog.getOpenFileNames is called
         result = FileDialog.getOpenFileNames(self.mocked_parent)
@@ -68,6 +70,7 @@
         call_list = [call('/Valid File'), call('/url%20encoded%20file%20%231'), call('/url encoded file #1'),
                      call('/non-existing'), call('/non-existing')]
         self.mocked_os.path.exists.assert_has_calls(call_list)
-        self.mocked_qt_gui.QmessageBox.information.called_with(self.mocked_parent, UiStrings().FileNotFound,
-                                                               UiStrings().FileNotFoundMessage % '/non-existing')
+        self.mocked_qt_gui.QMessageBox.information.assert_called_with(
+            self.mocked_parent, 'File Not Found',
+            'File /non-existing not found.\nPlease try selecting it individually.')
         self.assertEqual(result, ['/Valid File', '/url encoded file #1'], 'The returned file list is incorrect')

_______________________________________________
Mailing list: https://launchpad.net/~openlp-core
Post to     : openlp-core@lists.launchpad.net
Unsubscribe : https://launchpad.net/~openlp-core
More help   : https://help.launchpad.net/ListHelp

Reply via email to