spv-dev team mailing list archive
-
spv-dev team
-
Mailing list archive
-
Message #00040
[Merge] lp:~claude-bolduc/slidepresenterview/choose-projector-screens into lp:slidepresenterview
C. Bolduc has proposed merging lp:~claude-bolduc/slidepresenterview/choose-projector-screens into lp:slidepresenterview.
Requested reviews:
SlidePresenterView Development Team (spv-dev)
Implement the feature presenter-choose-projector-screens.
--
https://code.launchpad.net/~claude-bolduc/slidepresenterview/choose-projector-screens/+merge/30878
Your team SlidePresenterView Development Team is requested to review the proposed merge of lp:~claude-bolduc/slidepresenterview/choose-projector-screens into lp:slidepresenterview.
=== modified file '.bzrignore'
--- .bzrignore 2010-05-03 02:19:38 +0000
+++ .bzrignore 2010-07-25 04:39:42 +0000
@@ -6,3 +6,4 @@
slidepresenterview/ui/qt_forms/*.py
run_spv.bat
slidepresenterview.egg-info
+*.pro.user
=== modified file 'HACKING'
--- HACKING 2010-07-11 17:27:55 +0000
+++ HACKING 2010-07-25 04:39:42 +0000
@@ -14,13 +14,7 @@
* Since 2010-01, we use a patched version of Mock. That version
in already included in thirdparty/mock.py.
- Freshen (for functionnal tests)
- * Since 2010-05, we use a pre-release of Freshen 0.2 (currently
- the Master branch) available for download at:
- http://github.com/rlisagor/freshen
- To install it:
- python setup.py install
- - PyYaml (needed by Freshen)
- * easy_install pyyaml
+ * easy_install freshen
How to compile/generate UI files
=== added file 'resources/spv_qtproject.pro'
--- resources/spv_qtproject.pro 1970-01-01 00:00:00 +0000
+++ resources/spv_qtproject.pro 2010-07-25 04:39:42 +0000
@@ -0,0 +1,6 @@
+QT += svg \
+ xml
+TARGET = slidepresenterview_form
+TEMPLATE = app
+FORMS += ui/console.ui \
+ ui/preferred_projectors.ui
=== modified file 'resources/ui/console.ui'
--- resources/ui/console.ui 2009-07-04 22:34:33 +0000
+++ resources/ui/console.ui 2010-07-25 04:39:42 +0000
@@ -109,7 +109,7 @@
<x>0</x>
<y>0</y>
<width>800</width>
- <height>24</height>
+ <height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@@ -124,8 +124,10 @@
<property name="title">
<string>Presentation</string>
</property>
- <addaction name="action_start"/>
- <addaction name="action_stop"/>
+ <addaction name="action_show_presentation"/>
+ <addaction name="action_end_presentation"/>
+ <addaction name="separator"/>
+ <addaction name="action_configure_preferred_projectors"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuPresentation"/>
@@ -135,38 +137,31 @@
<property name="text">
<string>Open...</string>
</property>
- <property name="shortcut">
- <string>Ctrl+O</string>
- </property>
</action>
<action name="action_exit">
<property name="text">
<string>Exit</string>
</property>
- <property name="shortcut">
- <string>Ctrl+Q</string>
- </property>
- </action>
- <action name="action_start">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Start</string>
- </property>
- <property name="shortcut">
- <string>Ctrl+L</string>
- </property>
- </action>
- <action name="action_stop">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Stop</string>
- </property>
- <property name="shortcut">
- <string>Ctrl+E</string>
+ </action>
+ <action name="action_show_presentation">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Show</string>
+ </property>
+ </action>
+ <action name="action_end_presentation">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>End</string>
+ </property>
+ </action>
+ <action name="action_configure_preferred_projectors">
+ <property name="text">
+ <string>Configure preferred projector(s)</string>
</property>
</action>
</widget>
=== added file 'resources/ui/preferred_projectors.ui'
--- resources/ui/preferred_projectors.ui 1970-01-01 00:00:00 +0000
+++ resources/ui/preferred_projectors.ui 2010-07-25 04:39:42 +0000
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>preferred_projectors</class>
+ <widget class="QWidget" name="preferred_projectors">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>180</width>
+ <height>207</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>180</width>
+ <height>207</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>250</width>
+ <height>300</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>Preferred projector(s)</string>
+ </property>
+ <property name="locale">
+ <locale language="English" country="Canada"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Show presentation on</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="other_screens_button">
+ <property name="text">
+ <string>other screen(s)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="selected_screens_button">
+ <property name="text">
+ <string>selected screen(s):</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_2" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>2</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QListWidget" name="selected_screens_list">
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::NoSelection</enum>
+ </property>
+ <property name="viewMode">
+ <enum>QListView::ListMode</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>10</width>
+ <height>2</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="refresh_button">
+ <property name="text">
+ <string> Refresh screen(s) </string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_3" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="apply_button">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Apply</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
=== modified file 'setup.cfg'
--- setup.cfg 2010-07-11 17:27:55 +0000
+++ setup.cfg 2010-07-25 04:39:42 +0000
@@ -3,6 +3,7 @@
with-doctest=1
#detailed-errors=1
with-freshen=1
+tags=~pending
testmatch=(?:^|[\b_\.%s-])([Tt]est|should)
where=slidepresenterview/
exclude=slidepresenterview/tests/manual
=== modified file 'slidepresenterview/__init__.py'
--- slidepresenterview/__init__.py 2010-01-07 04:29:41 +0000
+++ slidepresenterview/__init__.py 2010-07-25 04:39:42 +0000
@@ -25,7 +25,7 @@
##########
# Packages
#####
-import sys
+import os, sys
from itertools import imap
@@ -207,7 +207,29 @@
return False
return True
-
+
+
+def _load_stylesheet():
+ common_stylesheet = _load_stylesheet_for_platform('all')
+ specific_stylesheet = _load_stylesheet_for_platform(sys.platform)
+ return common_stylesheet + specific_stylesheet
+
+
+def _load_stylesheet_for_platform(platform):
+ try:
+ from slidepresenterview.config import qt_configuration
+
+ qss = ""
+ current_dir = os.path.dirname(__file__)
+ for qss_filename in qt_configuration.QSS_LIST_FOR_PLATFORM[platform]:
+ qss_file = os.path.join(current_dir, qss_filename)
+ with open(qss_file, "r") as file:
+ qss = qss + file.read()
+ return qss
+ except:
+ return "" # There is no style sheet.
+
+
def main_gui():
if not check_env():
@@ -217,10 +239,15 @@
from slidepresenterview.ui import console_window
from slidepresenterview.ui import presentation
+ from slidepresenterview.config import user_configuration
app = QtGui.QApplication(sys.argv)
+ stylesheet = _load_stylesheet()
+ app.setStyleSheet(stylesheet)
+ user_config = user_configuration.UserConfiguration()
presentation_mediator = presentation.Presentation()
- window = console_window.ConsoleWindow(presentation_mediator)
+ screen_information_provider = QtGui.QApplication.desktop()
+ window = console_window.ConsoleWindow(user_config, presentation_mediator,
+ screen_information_provider)
window.show()
sys.exit(app.exec_())
-
=== added directory 'slidepresenterview/config'
=== added file 'slidepresenterview/config/__init__.py'
--- slidepresenterview/config/__init__.py 1970-01-01 00:00:00 +0000
+++ slidepresenterview/config/__init__.py 2010-07-25 04:39:42 +0000
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+#
+# SlidePresenterView - Console for presenters
+# https://launchpad.net/slidepresenterview
+#
+# Copyright (C) 2010 Claude Bolduc <claude.bolduc _AT@. gmail.com>
+#
+# 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+#
+"""
+Configurations used by SPV.
+"""
=== added file 'slidepresenterview/config/qt_configuration.py'
--- slidepresenterview/config/qt_configuration.py 1970-01-01 00:00:00 +0000
+++ slidepresenterview/config/qt_configuration.py 2010-07-25 04:39:42 +0000
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+#
+# SlidePresenterView - Console for presenters
+# https://launchpad.net/slidepresenterview
+#
+# Copyright (C) 2010 Claude Bolduc <claude.bolduc _AT@. gmail.com>
+#
+# 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+#
+"""
+Configurations used by SPV for the Qt environment.
+
+It is loaded at the start of the application.
+"""
+
+QSS_LIST_FOR_PLATFORM = {
+ 'all': ['ui/qt_forms/qss/common.qss'],
+ 'win32': ['ui/qt_forms/qss/windows.qss'],
+ 'cygwin': [],
+ 'darwin': [],
+ 'linux2': []
+}
=== added file 'slidepresenterview/config/user_configuration.py'
--- slidepresenterview/config/user_configuration.py 1970-01-01 00:00:00 +0000
+++ slidepresenterview/config/user_configuration.py 2010-07-25 04:39:42 +0000
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+#
+# SlidePresenterView - Console for presenters
+# https://launchpad.net/slidepresenterview
+#
+# Copyright (C) 2010 Claude Bolduc <claude.bolduc _AT@. gmail.com>
+#
+# 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+#
+"""
+User-defined configurations for SPV.
+
+Some configurations may refer to elements of Qt. When doing so, we keep the element given by Qt.
+For example, the configuration for the `preferred_selected_screens_as_projector` is a list
+of physical screen numbers as given by Qt (so it is 0-based).
+"""
+
+class UserConfiguration(object):
+
+ def __init__(self):
+ self.must_show_preferred_projectors_at_startup = False
+ self.is_preferring_presentation_showed_on_other_screens = True
+ self.preferred_selected_screens_as_projector = []
+
+
+ def is_screen_selected_as_preferred_projector(self, screen_number):
+ return screen_number in self.preferred_selected_screens_as_projector
=== added file 'slidepresenterview/tests/functional/choose_projector_screens.feature'
--- slidepresenterview/tests/functional/choose_projector_screens.feature 1970-01-01 00:00:00 +0000
+++ slidepresenterview/tests/functional/choose_projector_screens.feature 2010-07-25 04:39:42 +0000
@@ -0,0 +1,64 @@
+Using step definitions from: 'steps/qt_environment_steps', 'steps/preferred_projectors_steps'
+
+Feature: Choose the projector screens to show the presentation
+
+ In order to give my talk
+ As a presenter
+ I want to be able to choose the projector screens to show the presentation.
+
+
+ Background:
+ Given I have 2 screens
+ And I can select my preferred projectors
+
+
+ Scenario: Hot plugging a screen
+ Given I hot plug a screen
+ When I refresh the available screens
+ Then 3 screens are listed
+
+
+ Scenario: Hot unplugging a screen
+ Given I hot unplug a screen
+ When I refresh the available screens
+ Then 1 screen is listed
+
+
+ Scenario: Hot unplugging all screens
+ Given I hot unplug all screens
+ When I refresh the available screens
+ Then 0 screen is listed
+
+
+ Scenario: Selecting other screens as projectors
+ When I select other screens as projectors
+ And I apply the changes
+ Then the other screens are selected as projectors
+
+
+ Scenario Outline: Selecting screens as projector
+ When I select screens <screens> as projectors
+ And I apply the changes
+ Then screens <screens> are selected as projectors
+ And the other screens are not selected as projectors
+ Examples:
+ | screens |
+ | 1 |
+ | 2 |
+ | 1, 2 |
+
+
+ Scenario: Applying the changes stores current view
+ When I select screen 2 as projectors
+ And I select other screens as projectors
+ And I apply the changes
+ Then the other screens are selected as projectors
+ And screen 2 is selected as projector
+
+
+ Scenario: Bumping old preferences that do not exist in the current configuration
+ Given my old preference was to select screens 1 and 3 as projectors
+ When I select other screens as projectors
+ And I apply the changes
+ Then the other screens are selected as projectors
+ And screen 1 is selected as projector
=== modified file 'slidepresenterview/tests/functional/steps/document_steps.py'
--- slidepresenterview/tests/functional/steps/document_steps.py 2010-05-03 00:34:47 +0000
+++ slidepresenterview/tests/functional/steps/document_steps.py 2010-07-25 04:39:42 +0000
@@ -63,8 +63,10 @@
@Given("the document ([A-Z0-9_]+) opened at page (\d+|None)[.]?$")
def set_already_doc_at_page(doc, page):
- run_steps('Given I previously opened the document %s' % doc)
- run_steps('Given is currently at page %s' % page)
+ run_steps("""
+ Given I previously opened the document %s
+ And is currently at page %s
+ """ % (doc, page))
@Given("is currently at page (\d+|None).*")
def set_already_at_page(page):
@@ -141,8 +143,10 @@
@Then("the document ([A-Z0-9_]*|None) is(?: still)? opened at page (\d+|None)")
def check_opened_at_page(doc, page):
- run_steps('Then the document %s is still opened' % doc)
- run_steps('Then is at page %s' % page)
+ run_steps("""
+ Then the document %s is still opened
+ And is at page %s
+ """ % (doc, page))
@Then("the document ([A-Z0-9_]*|None) is(?: still)? opened[.]?$")
def check_doc_opened(doc):
@@ -156,8 +160,10 @@
@Then("the requested document is opened at page (\d+|None)$")
def check_requested_doc_at_page(page):
- run_steps('Then the requested document is opened')
- run_steps('Then is at page %s' % page)
+ run_steps("""
+ Then the requested document is opened
+ And is at page %s
+ """ % page)
@Then("the requested document is opened$")
def check_requested_doc():
@@ -204,8 +210,10 @@
@Then("both buttons are (enabled|disabled)[.]?$")
def check_both_buttons(status):
- run_steps('Then the next button is %s' % status)
- run_steps('Then the previous button is %s' % status)
+ run_steps("""
+ Then the next button is %s
+ And the previous button is %s
+ """ % (status, status))
@Then("no warning was shown")
def check_no_warning():
=== added file 'slidepresenterview/tests/functional/steps/preferred_projectors_steps.py'
--- slidepresenterview/tests/functional/steps/preferred_projectors_steps.py 1970-01-01 00:00:00 +0000
+++ slidepresenterview/tests/functional/steps/preferred_projectors_steps.py 2010-07-25 04:39:42 +0000
@@ -0,0 +1,153 @@
+# -*- coding: utf-8 -*-
+#
+# SlidePresenterView - Console for presenters
+# https://launchpad.net/slidepresenterview
+#
+# Copyright (C) 2010 Claude Bolduc <claude.bolduc _AT@. gmail.com>
+#
+# 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+#
+
+"""
+Step definitions when configuring the preferred projectors.
+"""
+__all__ = []
+
+from PyQt4 import QtCore, QtGui
+
+from mock import Mock
+
+from freshen import *
+
+from slidepresenterview.config.user_configuration import UserConfiguration
+from slidepresenterview.ui.presentation import Presentation
+from slidepresenterview.ui.console_window import ConsoleWindow
+
+
+class _FakeScreenInformationProvider(object):
+
+ def __init__(self):
+ self.mock = Mock(spec=QtGui.QDesktopWidget)
+
+
+ def set_fake_screens(self, number_of_screens):
+ self.mock.numScreens.return_value = number_of_screens
+
+
+ def add_fake_screens(self, number_of_screens_added):
+ old_number_of_screens = self.mock.numScreens()
+ new_number_of_screens = old_number_of_screens + number_of_screens_added
+ self.set_fake_screens(new_number_of_screens)
+
+
+@Before
+def create_fake_screen_info_provider(scenario):
+ scc.mock_screen_info_provider = _FakeScreenInformationProvider()
+
+
+@Transform(r"^(\d+) screen$")
+def transform_number_of_screens(number_of_screens):
+ return int(number_of_screens)
+
+@Transform(r"^screen[s]? (.+)$")
+def transform_screens(screens):
+ screens_string = screens.split(',')
+ screens_int = [int(screen_string.strip()) for screen_string in screens_string]
+ return screens_int
+
+
+@Given("^I can select my preferred projectors$")
+def can_select_projectors():
+ scc.user_config = UserConfiguration()
+ presentation_mediator = Presentation()
+ scc.win = ConsoleWindow(scc.user_config, presentation_mediator,
+ scc.mock_screen_info_provider.mock)
+ scc.pref_projectors = scc.win.pref_projectors
+
+@Given("^I have (\d+ screen)[s]?$")
+def have_number_of_screens(number_of_screens):
+ scc.mock_screen_info_provider.set_fake_screens(number_of_screens)
+
+@Given("^I hot plug a screen$")
+def hot_plugging_a_screen():
+ scc.mock_screen_info_provider.add_fake_screens(1)
+
+@Given("^I hot unplug a screen$")
+def hot_unplugging_a_screen():
+ scc.mock_screen_info_provider.add_fake_screens(-1)
+
+@Given("^I hot unplug all screens$")
+def hot_unplugging_all_screens():
+ scc.mock_screen_info_provider.set_fake_screens(0)
+
+@Given("^my old preference was to select screens 1 and 3 as projectors$")
+def set_old_preference():
+ scc.user_config.is_preferring_presentation_showed_on_other_screens = False
+ scc.user_config.preferred_selected_screens_as_projector = [0, 2]
+ scc.pref_projectors.on_refresh_button_clicked(True)
+
+
+@When("^I select other screens as projectors$")
+def select_other_screens_as_projectors():
+ scc.pref_projectors.on_other_screens_button_toggled(True)
+
+@When("^I select (screen[s]? .+) as projector[s]?$")
+def select_specific_screens_as_projectors(logical_screens):
+ scc.pref_projectors.on_selected_screens_button_toggled(True)
+
+ num_available_screens = scc.pref_projectors.selected_screens_list.count()
+ if num_available_screens < max(logical_screens):
+ _fail("Cannot select a screen as projector that have a number bigger than"
+ + " the number of available screens.")
+
+ for index in range(num_available_screens):
+ _set_check_state_for_item_at_according_to(index, logical_screens)
+
+def _fail(message):
+ assert_true(False, message)
+
+def _set_check_state_for_item_at_according_to(physical_index, logical_screens):
+ item = scc.pref_projectors.selected_screens_list.item(physical_index)
+ logical_index = physical_index + 1
+ if logical_index in logical_screens:
+ item.setCheckState(QtCore.Qt.Checked)
+ else:
+ item.setCheckState(QtCore.Qt.Unchecked)
+
+@When("^I refresh the available screens$")
+def refresh_screens():
+ scc.pref_projectors.on_refresh_button_clicked(True)
+
+@When("^I apply the changes$")
+def apply_changes():
+ scc.pref_projectors.on_apply_button_clicked(True)
+
+
+@Then("^the other screens are selected as projectors$")
+def check_other_screens_selected():
+ assert_true(scc.user_config.is_preferring_presentation_showed_on_other_screens)
+
+@Then("^(\d+ screen)[s]? (?:are|is) listed$")
+def check_number_of_screens(number_of_screens):
+ num_listed_screens = scc.pref_projectors.selected_screens_list.count()
+ assert_equal(num_listed_screens, number_of_screens)
+
+@Then("^(screen[s]? .+) (?:are|is) selected as projector[s]?$")
+def check_screens_selected(logical_screens):
+ physical_screens = [logical_screen - 1 for logical_screen in logical_screens]
+ assert_equal(scc.user_config.preferred_selected_screens_as_projector, physical_screens)
+
+@Then("^the other screens are not selected as projectors$")
+def check_other_screens_not_selected():
+ assert_false(scc.user_config.is_preferring_presentation_showed_on_other_screens)
\ No newline at end of file
=== modified file 'slidepresenterview/tests/functional/steps/qt_environment_steps.py'
--- slidepresenterview/tests/functional/steps/qt_environment_steps.py 2010-05-03 02:50:56 +0000
+++ slidepresenterview/tests/functional/steps/qt_environment_steps.py 2010-07-25 04:39:42 +0000
@@ -28,6 +28,7 @@
from freshen import Before, After, scc, glc
from slidepresenterview.utils import pyqt as pyqtutils
+from slidepresenterview.config import user_configuration
from slidepresenterview.ui import presentation
from slidepresenterview.ui.console_window import ConsoleWindow
@@ -38,8 +39,10 @@
glc.app = QtGui.QApplication([])
QtCore.qInstallMsgHandler(pyqtutils.msg_handler_no_message)
+ scc.user_config = user_configuration.UserConfiguration()
scc.presentation_mediator = presentation.Presentation()
- scc.win = ConsoleWindow(scc.presentation_mediator)
+ scc.screen_info_provider = QtGui.QApplication.desktop()
+ scc.win = ConsoleWindow(scc.user_config, scc.presentation_mediator, scc.screen_info_provider)
scc.slide_view = scc.win.current_slide_view
@After
=== modified file 'slidepresenterview/ui/console_window.py'
--- slidepresenterview/ui/console_window.py 2010-05-02 23:36:17 +0000
+++ slidepresenterview/ui/console_window.py 2010-07-25 04:39:42 +0000
@@ -30,6 +30,8 @@
from PyQt4 import QtGui
from slidepresenterview.ui.qt_forms.console import Ui_console_window
+from slidepresenterview.ui.widgets.preferred_projectors import \
+ PreferredProjectors
from slidepresenterview.utils import pyqt as pyqtutils
class ConsoleWindow(QtGui.QMainWindow, # pylint: disable-msg=E1101
@@ -41,29 +43,55 @@
@ivar presentation_mediator: a presentation mediator.
"""
- def __init__(self, presentation_mediator):
- """
- Constructor. Set up the UI and manage the presentation mediator.
-
- @param presentation_mediator: the presentation mediator.
- """
+ def __init__(self, user_config, presentation_mediator, screen_information_provider):
QtGui.QMainWindow.__init__(self) # pylint: disable-msg=E1101
Ui_console_window.__init__(self)
self.setupUi(self)
self.set_presentation_mediator(presentation_mediator)
presentation_mediator.register_console_window(self)
- self.current_slide_view.set_presentation_mediator(\
- presentation_mediator)
- presentation_mediator.register_current_slide_view(\
- self.current_slide_view)
+ self.current_slide_view.set_presentation_mediator(presentation_mediator)
+ presentation_mediator.register_current_slide_view(self.current_slide_view)
# Disables buttons by default (mainly because we must be sure that
# the workaround for some versions of Qt is applied).
pyqtutils.set_button_enabled(self.current_slide_next_button, False)
pyqtutils.set_button_enabled(self.current_slide_previous_button, False)
-
+ self._set_shortcuts_for_actions()
+
+ self._create_docks(user_config, screen_information_provider)
+
+
+ def _set_shortcuts_for_actions(self):
+ """
+ @note: We do not use QtCreator or designer to do this because
+ it does not seem to handle standard shortcuts and
+ multiple shortcuts.
+ """
+ self.action_open.setShortcut(QtGui.QKeySequence.Open)
+ self.action_exit.setShortcut(QtGui.QKeySequence.Close)
+ self.action_show_presentation.setShortcuts([QtCore.Qt.Key_F5,
+ QtCore.Qt.CTRL + QtCore.Qt.Key_L])
+ self.action_end_presentation.setShortcuts([QtCore.Qt.Key_Escape,
+ QtCore.Qt.CTRL + QtCore.Qt.Key_E])
+
+
+ def _create_docks(self, user_config, screen_information_provider):
+ self._dock_preferred_projectors = self._create_preferred_projectors_dock(user_config,
+ screen_information_provider)
+
+
+ def _create_preferred_projectors_dock(self, user_config, screen_information_provider):
+ self.pref_projectors = PreferredProjectors(user_config, screen_information_provider)
+ dock_widget = QtGui.QDockWidget("Preferred Projector(s)", self)
+ dock_widget.setWidget(self.pref_projectors)
+ dock_widget.setVisible(user_config.must_show_preferred_projectors_at_startup)
+ self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dock_widget)
+
+ return dock_widget
+
+
def set_presentation_mediator(self, presentation):
"""
Set the presentation mediator.
@@ -162,24 +190,27 @@
doc = self.presentation_mediator.document
if doc is None or not self.presentation_mediator.is_file_opened():
- pyqtutils.set_button_enabled(self.current_slide_next_button,
- False)
- pyqtutils.set_button_enabled(self.current_slide_previous_button,
- False)
+ pyqtutils.set_button_enabled(self.current_slide_next_button, False)
+ pyqtutils.set_button_enabled(self.current_slide_previous_button, False)
return
doc_page_count = doc.get_page_count()
if page < doc_page_count and page > 0:
- pyqtutils.set_button_enabled(self.current_slide_next_button,
- True)
+ pyqtutils.set_button_enabled(self.current_slide_next_button, True)
else:
- pyqtutils.set_button_enabled(self.current_slide_next_button,
- False)
+ pyqtutils.set_button_enabled(self.current_slide_next_button, False)
if page > 1 and page <= doc_page_count:
- pyqtutils.set_button_enabled(self.current_slide_previous_button,
- True)
- else:
- pyqtutils.set_button_enabled(self.current_slide_previous_button,
- False)
+ pyqtutils.set_button_enabled(self.current_slide_previous_button, True)
+ else:
+ pyqtutils.set_button_enabled(self.current_slide_previous_button, False)
+
+
+ def on_action_configure_preferred_projectors_triggered(self, checked=None):
+ if checked is None: return
+
+ if self._dock_preferred_projectors.isHidden():
+ self._dock_preferred_projectors.show()
+ else:
+ self._dock_preferred_projectors.hide()
=== added directory 'slidepresenterview/ui/qt_forms/qss'
=== added file 'slidepresenterview/ui/qt_forms/qss/common.qss'
--- slidepresenterview/ui/qt_forms/qss/common.qss 1970-01-01 00:00:00 +0000
+++ slidepresenterview/ui/qt_forms/qss/common.qss 2010-07-25 04:39:42 +0000
@@ -0,0 +1,38 @@
+/* SlidePresenterView - Console for presenters
+ * https://launchpad.net/slidepresenterview
+ *
+ * Copyright (C) 2010 Claude Bolduc <claude.bolduc _AT@. gmail.com>
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Common Qt style sheet for the whole SPV application. */
+
+* {
+ font-size: 15px; /* The font is big.
+ This eases reading when presenting. */
+}
+
+QPushButton {
+ min-width: 80px;
+}
+
+QRadioButton:hover {
+ background-color: #ccccff;
+}
+
+QGroupBox {
+ font-size: 20px;
+ color: #bbbbbb;
+}
=== added file 'slidepresenterview/ui/qt_forms/qss/windows.qss'
--- slidepresenterview/ui/qt_forms/qss/windows.qss 1970-01-01 00:00:00 +0000
+++ slidepresenterview/ui/qt_forms/qss/windows.qss 2010-07-25 04:39:42 +0000
@@ -0,0 +1,45 @@
+/* SlidePresenterView - Console for presenters
+ * https://launchpad.net/slidepresenterview
+ *
+ * Copyright (C) 2010 Claude Bolduc <claude.bolduc _AT@. gmail.com>
+ *
+ * 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Qt style sheet for the whole SPV application
+ specific to the Windows platform. */
+
+QMenuBar {
+ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,
+ stop:0 lightgray, stop:1 darkgray);
+}
+
+QMenuBar::item {
+ background: transparent;
+}
+
+QMenuBar::item:selected {
+ background: #a8a8a8;
+}
+
+QMenuBar::item:pressed {
+ background: #888888;
+}
+
+QToolTip {
+ border: 2px solid #ffffcc;
+ padding: 5px;
+ border-radius: 3px;
+ opacity: 200;
+}
=== added file 'slidepresenterview/ui/widgets/preferred_projectors.py'
--- slidepresenterview/ui/widgets/preferred_projectors.py 1970-01-01 00:00:00 +0000
+++ slidepresenterview/ui/widgets/preferred_projectors.py 2010-07-25 04:39:42 +0000
@@ -0,0 +1,170 @@
+# -*- coding: utf-8 -*-
+#
+# SlidePresenterView - Console for presenters
+# https://launchpad.net/slidepresenterview
+#
+# Copyright (C) 2010 Claude Bolduc <claude.bolduc _AT@. gmail.com>
+#
+# 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+#
+"""
+The preferred projectors configuration widget for SlidePresenterView.
+"""
+
+##########
+# Imports
+#####
+from PyQt4 import QtCore # pylint: disable-msg=E0611
+from PyQt4 import QtGui
+
+from slidepresenterview.ui.qt_forms.preferred_projectors import Ui_preferred_projectors
+
+class PreferredProjectors(QtGui.QWidget, Ui_preferred_projectors):# pylint: disable-msg=E1101
+ """
+ The preferred projectors configuration widget for SlidePresenterView.
+
+ :ivar user_config: User-defined configuration.
+ """
+
+ def __init__(self, user_config, screen_information_provider, parent=None):
+ """
+ :type screen_information_provider: QtGui.QDesktopWidget
+
+ :param parent: The parent of the widget (if it is the default, then
+ the widget becomes a window).
+ """
+ QtGui.QWidget.__init__(self, parent) # pylint: disable-msg=E1101
+ Ui_preferred_projectors.__init__(self)
+ self.setupUi(self)
+
+ self._user_config = user_config
+ self._screen_information_provider = screen_information_provider
+ self._add_list_available_screens()
+ self._check_radio_button_for_user_config_choice()
+
+
+ def _add_list_available_screens(self):
+ num_screens = self._screen_information_provider.numScreens()
+ for physical_screen_number in range(num_screens):
+ self._add_screen_item(physical_screen_number)
+
+
+ def _add_screen_item(self, physical_screen_number):
+ screen_name = self._create_screen_name(physical_screen_number)
+ screen_item = QtGui.QListWidgetItem(screen_name, self.selected_screens_list)
+ self._set_check_state(screen_item, physical_screen_number)
+
+
+ def _create_screen_name(self, physical_screen_number):
+ screen_size = self._screen_information_provider.screenGeometry(physical_screen_number)
+ identify_if_current_screen = self._get_identify_if_current_screen(physical_screen_number)
+ logical_screen_number = self._get_logical_screen_number(physical_screen_number)
+ return 'Screen %s (%sx%s)%s' % (logical_screen_number,
+ screen_size.width(),
+ screen_size.height(),
+ identify_if_current_screen)
+
+
+ def _get_identify_if_current_screen(self, physical_screen_number):
+ if self._is_current_screen(physical_screen_number):
+ return " [current]"
+ else:
+ return ""
+
+
+ def _get_logical_screen_number(self, physical_screen_number):
+ return physical_screen_number + 1
+
+
+ def _is_current_screen(self, physical_screen_number):
+ return physical_screen_number == self._screen_information_provider.screenNumber(self)
+
+
+ def _set_check_state(self, screen_item, physical_screen_number):
+ screen_item.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
+
+ if self._user_config.is_screen_selected_as_preferred_projector(physical_screen_number):
+ screen_item.setCheckState(QtCore.Qt.Checked)
+ else:
+ screen_item.setCheckState(QtCore.Qt.Unchecked)
+
+
+ def _check_radio_button_for_user_config_choice(self):
+ if self._user_config.is_preferring_presentation_showed_on_other_screens:
+ self._enable_other_screens_button()
+ else:
+ self._enable_selected_screens_button()
+
+
+ def _enable_other_screens_button(self):
+ self.other_screens_button.setChecked(True)
+ self.selected_screens_list.setEnabled(False)
+
+
+ def _enable_selected_screens_button(self):
+ self.selected_screens_button.setChecked(True)
+ self.selected_screens_list.setEnabled(True)
+
+
+ def on_other_screens_button_toggled(self, checked=None):
+ if checked is None: return
+ if not checked: return
+
+ self._enable_other_screens_button()
+
+
+ def on_selected_screens_button_toggled(self, checked=None):
+ if checked is None: return
+ if not checked: return
+
+ self._enable_selected_screens_button()
+
+
+ def on_refresh_button_clicked(self, checked=None):
+ if checked is None: return
+
+ self.selected_screens_list.clear()
+ self._add_list_available_screens()
+
+
+ def on_apply_button_clicked(self, checked=None):
+ if checked is None: return
+
+ self._set_is_preferring_presentation_showed_on_other_screens()
+ self._set_preferred_selected_screens_as_projector()
+
+
+ def _set_is_preferring_presentation_showed_on_other_screens(self):
+ is_checked = self.other_screens_button.isChecked()
+ self._user_config.is_preferring_presentation_showed_on_other_screens = is_checked
+
+
+
+ def _set_preferred_selected_screens_as_projector(self):
+ selected_screens_numbers = self._get_all_selected_screens_numbers()
+ self._user_config.preferred_selected_screens_as_projector = selected_screens_numbers
+
+
+ def _get_all_selected_screens_numbers(self):
+ selected_screens = []
+ for physical_screen_number in range(self.selected_screens_list.count()):
+ if self._is_screen_checked(physical_screen_number):
+ selected_screens.append(physical_screen_number)
+
+ return selected_screens
+
+
+ def _is_screen_checked(self, physical_screen_number):
+ screen_item = self.selected_screens_list.item(physical_screen_number)
+ return screen_item.checkState() == QtCore.Qt.Checked
\ No newline at end of file
Follow ups