qtmeetings sources to Maemo garage
authorOssi Jormakka <ossi.jormakka@ixonos.com>
Tue, 19 May 2009 06:25:11 +0000 (09:25 +0300)
committerOssi Jormakka <ossi.jormakka@ixonos.com>
Tue, 19 May 2009 06:25:11 +0000 (09:25 +0300)
166 files changed:
QtMeetings.conf [new file with mode: 0644]
QtMeetings.desktop [new file with mode: 0644]
QtMeetings.doxygen [new file with mode: 0644]
QtMeetings.pro [new file with mode: 0644]
debian/README.Debian [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/changelog.Debian [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/postinst [new file with mode: 0644]
debian/postrm [new file with mode: 0644]
debian/preinst [new file with mode: 0644]
debian/qtmeetings.install [new file with mode: 0644]
debian/qtmeetings/DEBIAN/conffiles [new file with mode: 0644]
debian/qtmeetings/DEBIAN/control [new file with mode: 0644]
debian/qtmeetings/DEBIAN/md5sums [new file with mode: 0644]
debian/qtmeetings/DEBIAN/postinst [new file with mode: 0755]
debian/qtmeetings/DEBIAN/postrm [new file with mode: 0755]
debian/qtmeetings/DEBIAN/preinst [new file with mode: 0755]
debian/qtmeetings/etc/QtMeetings.conf [new file with mode: 0644]
debian/qtmeetings/etc/init.d/qtmeetings-launcher [new file with mode: 0755]
debian/qtmeetings/usr/bin/qtmeetings [new file with mode: 0755]
debian/qtmeetings/usr/bin/qtmeetings-devstopper [new file with mode: 0755]
debian/qtmeetings/usr/bin/qtmeetings-rename [new file with mode: 0755]
debian/qtmeetings/usr/bin/qtmeetings-updatercd [new file with mode: 0755]
debian/qtmeetings/usr/share/applications/hildon/QtMeetings.desktop [new file with mode: 0644]
debian/qtmeetings/usr/share/doc/qtmeetings/README.Debian [new file with mode: 0644]
debian/qtmeetings/usr/share/doc/qtmeetings/copyright [new file with mode: 0644]
debian/rules [new file with mode: 0644]
resources/BusinessLogic.qrc [new file with mode: 0644]
resources/UserInterface.qrc [new file with mode: 0644]
resources/icons/arrow_left.png [new file with mode: 0644]
resources/icons/arrow_right.png [new file with mode: 0644]
resources/icons/button_current.png [new file with mode: 0644]
resources/icons/button_settings.png [new file with mode: 0644]
resources/icons/popup_cancel.png [new file with mode: 0644]
resources/icons/popup_error.png [new file with mode: 0644]
resources/icons/popup_information.png [new file with mode: 0644]
resources/icons/popup_ok.png [new file with mode: 0644]
resources/icons/popup_question.png [new file with mode: 0644]
resources/icons/popup_warning.png [new file with mode: 0644]
resources/icons/roomstatus_busy.png [new file with mode: 0644]
resources/icons/roomstatus_free.png [new file with mode: 0644]
resources/xml/errortable.xml [new file with mode: 0644]
scripts/qtmeetings-devstopper [new file with mode: 0755]
scripts/qtmeetings-launcher [new file with mode: 0755]
scripts/qtmeetings-rename [new file with mode: 0755]
scripts/qtmeetings-updatercd [new file with mode: 0755]
src/BusinessLogic/Engine.cpp [new file with mode: 0644]
src/BusinessLogic/Engine.h [new file with mode: 0644]
src/BusinessLogic/Utils/Clock.cpp [new file with mode: 0644]
src/BusinessLogic/Utils/Clock.h [new file with mode: 0644]
src/BusinessLogic/Utils/ErrorMapper.cpp [new file with mode: 0644]
src/BusinessLogic/Utils/ErrorMapper.h [new file with mode: 0644]
src/Domain/Configuration/Configuration.cpp [new file with mode: 0644]
src/Domain/Configuration/Configuration.h [new file with mode: 0644]
src/Domain/Configuration/ConnectionSettings.cpp [new file with mode: 0644]
src/Domain/Configuration/ConnectionSettings.h [new file with mode: 0644]
src/Domain/Configuration/DisplaySettings.cpp [new file with mode: 0644]
src/Domain/Configuration/DisplaySettings.h [new file with mode: 0644]
src/Domain/Configuration/StartupSettings.cpp [new file with mode: 0644]
src/Domain/Configuration/StartupSettings.h [new file with mode: 0644]
src/Domain/Meeting.cpp [new file with mode: 0644]
src/Domain/Meeting.h [new file with mode: 0644]
src/Domain/Room.cpp [new file with mode: 0644]
src/Domain/Room.h [new file with mode: 0644]
src/IO/Communication/Communication.cpp [new file with mode: 0644]
src/IO/Communication/Communication.h [new file with mode: 0644]
src/IO/Communication/CommunicationManager.cpp [new file with mode: 0644]
src/IO/Communication/CommunicationManager.h [new file with mode: 0644]
src/IO/Communication/MessagingUtils.cpp [new file with mode: 0644]
src/IO/Communication/MessagingUtils.h [new file with mode: 0644]
src/IO/DeviceControl/AlarmSender.cpp [new file with mode: 0644]
src/IO/DeviceControl/AlarmSender.h [new file with mode: 0644]
src/IO/DeviceControl/DeviceConfigurator.cpp [new file with mode: 0644]
src/IO/DeviceControl/DeviceConfigurator.h [new file with mode: 0644]
src/IO/DeviceControl/DeviceConstants.h [new file with mode: 0644]
src/IO/DeviceControl/DeviceDataStorage.cpp [new file with mode: 0644]
src/IO/DeviceControl/DeviceDataStorage.h [new file with mode: 0644]
src/IO/DeviceControl/DeviceManager.cpp [new file with mode: 0644]
src/IO/DeviceControl/DeviceManager.h [new file with mode: 0644]
src/IO/DeviceControl/HWKeyListener.cpp [new file with mode: 0644]
src/IO/DeviceControl/HWKeyListener.h [new file with mode: 0644]
src/UserInterface/Components/DigitalTimeDisplayWidget.cpp [new file with mode: 0644]
src/UserInterface/Components/DigitalTimeDisplayWidget.h [new file with mode: 0644]
src/UserInterface/Components/MeetingRoomCombo.cpp [new file with mode: 0644]
src/UserInterface/Components/MeetingRoomCombo.h [new file with mode: 0644]
src/UserInterface/Components/ObservedWidget.cpp [new file with mode: 0644]
src/UserInterface/Components/ObservedWidget.h [new file with mode: 0644]
src/UserInterface/Components/ScheduleWidget.cpp [new file with mode: 0644]
src/UserInterface/Components/ScheduleWidget.h [new file with mode: 0644]
src/UserInterface/Components/TimeDisplayWidget.cpp [new file with mode: 0644]
src/UserInterface/Components/TimeDisplayWidget.h [new file with mode: 0644]
src/UserInterface/Utils/PasswordDialog.cpp [new file with mode: 0644]
src/UserInterface/Utils/PasswordDialog.h [new file with mode: 0644]
src/UserInterface/Utils/PopUpMessageBox.cpp [new file with mode: 0644]
src/UserInterface/Utils/PopUpMessageBox.h [new file with mode: 0644]
src/UserInterface/Utils/ToolBox.cpp [new file with mode: 0644]
src/UserInterface/Utils/ToolBox.h [new file with mode: 0644]
src/UserInterface/Views/MeetingInfoDialog.cpp [new file with mode: 0644]
src/UserInterface/Views/MeetingInfoDialog.h [new file with mode: 0644]
src/UserInterface/Views/RoomStatusIndicatorWidget.cpp [new file with mode: 0644]
src/UserInterface/Views/RoomStatusIndicatorWidget.h [new file with mode: 0644]
src/UserInterface/Views/SettingsView.cpp [new file with mode: 0644]
src/UserInterface/Views/SettingsView.h [new file with mode: 0644]
src/UserInterface/Views/WeeklyViewWidget.cpp [new file with mode: 0644]
src/UserInterface/Views/WeeklyViewWidget.h [new file with mode: 0644]
src/UserInterface/WindowManager.cpp [new file with mode: 0644]
src/UserInterface/WindowManager.h [new file with mode: 0644]
src/main.cpp [new file with mode: 0644]
tests/BusinessLogic/Engine/QtMeetings.conf [new file with mode: 0644]
tests/BusinessLogic/Engine/TestEngine.cpp [new file with mode: 0644]
tests/BusinessLogic/Engine/TestEngine.h [new file with mode: 0644]
tests/BusinessLogic/Engine/TestEngineOnly.cpp [new file with mode: 0644]
tests/BusinessLogic/Engine/TestEngineOnly.pro [new file with mode: 0644]
tests/BusinessLogic/Utils/Clock/TestClock.cpp [new file with mode: 0644]
tests/BusinessLogic/Utils/Clock/TestClock.h [new file with mode: 0644]
tests/BusinessLogic/Utils/Clock/TestClockOnly.cpp [new file with mode: 0644]
tests/BusinessLogic/Utils/Clock/TestClockOnly.pro [new file with mode: 0644]
tests/BusinessLogic/Utils/ErrorMapper/TestErrorMapper.cpp [new file with mode: 0644]
tests/BusinessLogic/Utils/ErrorMapper/TestErrorMapper.h [new file with mode: 0644]
tests/BusinessLogic/Utils/ErrorMapper/TestErrorMapperOnly.cpp [new file with mode: 0644]
tests/BusinessLogic/Utils/ErrorMapper/TestErrorMapperOnly.pro [new file with mode: 0644]
tests/Domain/Configuration/Configuration/QtMeetings.conf [new file with mode: 0644]
tests/Domain/Configuration/Configuration/TestConfiguration.cpp [new file with mode: 0644]
tests/Domain/Configuration/Configuration/TestConfiguration.h [new file with mode: 0644]
tests/Domain/Configuration/Configuration/TestConfigurationOnly.cpp [new file with mode: 0644]
tests/Domain/Configuration/Configuration/TestConfigurationOnly.pro [new file with mode: 0644]
tests/Domain/Configuration/ConnectionSettings/TestConnectionSettings.cpp [new file with mode: 0644]
tests/Domain/Configuration/ConnectionSettings/TestConnectionSettings.h [new file with mode: 0644]
tests/Domain/Configuration/ConnectionSettings/TestConnectionSettingsOnly.cpp [new file with mode: 0644]
tests/Domain/Configuration/ConnectionSettings/TestConnectionSettingsOnly.pro [new file with mode: 0644]
tests/Domain/Configuration/DisplaySettings/TestDisplaySettings.cpp [new file with mode: 0644]
tests/Domain/Configuration/DisplaySettings/TestDisplaySettings.h [new file with mode: 0644]
tests/Domain/Configuration/DisplaySettings/TestDisplaySettingsOnly.cpp [new file with mode: 0644]
tests/Domain/Configuration/DisplaySettings/TestDisplaySettingsOnly.pro [new file with mode: 0644]
tests/Domain/Configuration/StartupSettings/TestStartupSettings.cpp [new file with mode: 0644]
tests/Domain/Configuration/StartupSettings/TestStartupSettings.h [new file with mode: 0644]
tests/Domain/Configuration/StartupSettings/TestStartupSettingsOnly.cpp [new file with mode: 0644]
tests/Domain/Configuration/StartupSettings/TestStartupSettingsOnly.pro [new file with mode: 0644]
tests/Domain/Meeting/TestMeeting.cpp [new file with mode: 0644]
tests/Domain/Meeting/TestMeeting.h [new file with mode: 0644]
tests/Domain/Meeting/TestMeetingOnly.cpp [new file with mode: 0644]
tests/Domain/Meeting/TestMeetingOnly.pro [new file with mode: 0644]
tests/Domain/Room/TestRoom.cpp [new file with mode: 0644]
tests/Domain/Room/TestRoom.h [new file with mode: 0644]
tests/Domain/Room/TestRoomOnly.cpp [new file with mode: 0644]
tests/Domain/Room/TestRoomOnly.pro [new file with mode: 0644]
tests/IO/Communication/TestCommunication.cpp [new file with mode: 0644]
tests/IO/Communication/TestCommunication.h [new file with mode: 0644]
tests/IO/Communication/TestCommunicationOnly.cpp [new file with mode: 0644]
tests/IO/Communication/TestCommunicationOnly.pro [new file with mode: 0644]
tests/IO/Communication/input.xml [new file with mode: 0644]
tests/IO/CommunicationManager/TestCommunicationManager.cpp [new file with mode: 0644]
tests/IO/CommunicationManager/TestCommunicationManager.h [new file with mode: 0644]
tests/IO/CommunicationManager/TestCommunicationManagerOnly.cpp [new file with mode: 0644]
tests/IO/CommunicationManager/TestCommunicationManagerOnly.pro [new file with mode: 0644]
tests/QtMeetings.conf [new file with mode: 0644]
tests/TestQtMeetings.cpp [new file with mode: 0644]
tests/TestQtMeetings.pro [new file with mode: 0644]
tests/UserInterface/Components/MeetingRoomCombo/TestMeetingRoomCombo.cpp [new file with mode: 0644]
tests/UserInterface/Components/MeetingRoomCombo/TestMeetingRoomCombo.h [new file with mode: 0644]
tests/UserInterface/Components/MeetingRoomCombo/TestMeetingRoomComboOnly.cpp [new file with mode: 0644]
tests/UserInterface/Components/MeetingRoomCombo/TestMeetingRoomComboOnly.pro [new file with mode: 0644]
welcome [deleted file]

diff --git a/QtMeetings.conf b/QtMeetings.conf
new file mode 100644 (file)
index 0000000..7066087
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration password="admin" >
+
+       <connection>
+               <!-- TEST SERVER DATA-->
+               <!--<serverurl>192.168.0.35</serverurl>
+               <username>maemo</username>
+               <password>P@ssw0rd</password>-->
+               <serverurl>jklexch01.ixonos.com</serverurl>
+               <username></username>
+               <password></password>
+               <!-- interval is interpreted in seconds -->
+               <refreshinterval>60</refreshinterval>
+       </connection>
+
+       <startup>
+               <powersaving enabled="true" on="08:00" off="17:00" />
+       </startup>
+
+       <display>
+               <!-- only 5 or 7 days-long weeks are supported -->
+               <schedule>
+                       <week days="5" />
+                       <day startsat="08:00" endsat="17:00" />
+               </schedule>
+               <!-- date and time format strings must be compatible with Qt's QDateTime formatting  -->
+               <dateformat>ddd dd MMM</dateformat>
+               <timeformat>hh:mm</timeformat>
+       </display>
+
+    <rooms>
+               <!-- TEST SERVER DEFAULT ROOM
+               DO NOT FODGET TO DELETE THE DEFAULT="TRUE" ATTRIBUTE OF TAURUS
+               -->
+               <room>
+                       <name>TestRoom</name>
+                       <address>meetingroomtest@test.local</address>
+               </room>
+               
+               <room>
+                       <name>Pegasus</name>
+                       <address>meetingroom.pegasus_jyv@ixonos.com</address>
+               </room>
+               <room default="true">
+                       <name>Taurus</name>
+                       <address>meetingroom.taurus_jyv@ixonos.com</address>
+               </room>
+               <room>
+                       <name>Hercules</name>
+                       <address>meetingroom.hercules@ixonos.com</address>
+               </room>
+       </rooms>
+
+       <!-- language code must be in ISO 3166-1 alpha-2 standard -->
+       <language code="EN" />
+
+</configuration>
diff --git a/QtMeetings.desktop b/QtMeetings.desktop
new file mode 100644 (file)
index 0000000..c5c0587
--- /dev/null
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Encoding=UTF-8
+Version=1.0.3
+Type=Application
+Name=Qt Meetings
+Comment=Qt application to access meeting room's shared calendar.
+Exec=/usr/bin/qtmeetings
+Icon=qtmeetings
+X-HildonDesk-ShowInToolbar=true
+#X-Osso-Service=qtmeetings_app
+X-Osso-Type=application/x-executable
+Teminal=false
\ No newline at end of file
diff --git a/QtMeetings.doxygen b/QtMeetings.doxygen
new file mode 100644 (file)
index 0000000..a23465f
--- /dev/null
@@ -0,0 +1,1503 @@
+# Doxyfile 1.5.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file 
+# that follow. The default is UTF-8 which is also the encoding used for all 
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
+# iconv built into libc) for the transcoding. See 
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = QtMeetings
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, 
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), 
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, 
+# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, 
+# Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Java. For instance, namespaces will be presented as packages, qualified 
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
+# sources. Doxygen will then generate output that is tailored for 
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses. 
+# With this tag you can assign which parser to use for a given extension. 
+# Doxygen has a built-in mapping, but you can override or extend it using this tag. 
+# The format is ext=language, where ext is a file extension, and language is one of 
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, 
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat 
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), 
+# use: inc=Fortran f=C
+
+EXTENSION_MAPPING      = 
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
+# to include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to 
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter 
+# and setter methods for a property. Setting this option to YES (the default) 
+# will make doxygen to replace the get and set methods by a property in the 
+# documentation. This will only work if the methods are indeed getting or 
+# setting a simple type. If this is not the case, or you want to show the 
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
+# is documented as struct, union, or enum with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code in case the coding convention dictates that all compound 
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 
+# determine which symbols to keep in memory and which to flush to disk. 
+# When the cache is full, less often used symbols will be written to disk. 
+# For small to medium size projects (<1000 input files) the default value is 
+# probably good enough. For larger projects a too small cache size can cause 
+# doxygen to be busy swapping symbols to and from disk most of the time 
+# causing a significant performance penality. 
+# If the system has enough physical memory increasing the cache will improve the 
+# performance by keeping more symbols in memory. Note that the value works on 
+# a logarithmic scale so increasing the size by one will rougly double the 
+# memory usage. The cache size is given by this formula: 
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be 
+# extracted and appear in the documentation as a namespace called 
+# 'anonymous_namespace{file}', where file will be replaced with the base 
+# name of the file that contains the anonymous namespace. By default 
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
+# hierarchy of group names into alphabetical order. If set to NO (the default) 
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. 
+# This will remove the Files entry from the Quick Index and from the 
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
+# Namespaces page.  This will remove the Namespaces entry from the Quick Index 
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from 
+# the version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by 
+# doxygen. The layout file controls the global structure of the generated output files 
+# in an output format independent way. The create the layout file that represents 
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a 
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name 
+# of the layout file.
+
+LAYOUT_FILE            = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = .
+
+# This tag can be used to specify the character encoding of the source files 
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
+# also the default input encoding. Doxygen uses libiconv (or the iconv built 
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       = */test*/*
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the 
+# output. The symbol name can be a fully qualified name, a word, or if the 
+# wildcard * is used, a substring. Examples: ANamespace, AClass, 
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 
+# link to the source code.  Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files 
+# will be generated that can be used as input for Apple's Xcode 3 
+# integrated development environment, introduced with OSX 10.5 (Leopard). 
+# To create a documentation set, doxygen will generate a Makefile in the 
+# HTML output directory. Running make will produce the docset in that 
+# directory and running "make install" will install the docset in 
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
+# it at startup. 
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
+# feed. A documentation feed provides an umbrella under which multiple 
+# documentation sets from a single provider (such as a company or product suite) 
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
+# should uniquely identify the documentation set bundle. This should be a 
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file 
+# content.
+
+CHM_INDEX_ENCODING     = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER 
+# are set, an additional index file will be generated that can be used as input for 
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated 
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can 
+# be used to specify the file name of the resulting .qch file. 
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               = 
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = 
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. 
+# For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   = 
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see 
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  = 
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's 
+# filter section matches. 
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  = 
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 
+# be used to specify the location of Qt's qhelpgenerator. 
+# If non-empty doxygen will try to run qhelpgenerator on the generated 
+# .qhp file.
+
+QHG_LOCATION           = 
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 
+# structure should be generated to display hierarchical information. 
+# If the tag value is set to FRAME, a side panel will be generated 
+# containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature. Other possible values 
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories, 
+# and Class Hierarchy pages using a tree view instead of an ordered list; 
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which 
+# disables this behavior completely. For backwards compatibility with previous 
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE 
+# respectively.
+
+GENERATE_TREEVIEW      = NONE
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included 
+# as images in the HTML documentation. The default is 10. Note that 
+# when you change the font size after a successful doxygen run you need 
+# to manually remove any form_*.png images from the HTML output directory 
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#  
+# TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#  
+# TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links. 
+# Note that each tag file must have a unique name 
+# (where the name does NOT include the path) 
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see 
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
+# the mscgen tool resides. If left empty the tool is assumed to be found in the 
+# default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output 
+# directory and reference it in all dot files that doxygen generates. This 
+# font does not include all possible unicode characters however, so when you need 
+# these (or just want a differently looking font) you can specify the font name 
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font, 
+# which can be done by putting it in a standard location or by setting the 
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory 
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the 
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a 
+# different font using DOT_FONTNAME you can set the path where dot 
+# can find it using this tag.
+
+DOT_FONTPATH           = 
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
+# doxygen will generate a call dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable call graphs 
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
+# doxygen will generate a caller dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable caller 
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include 
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif 
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the 
+# number of direct children of the root node in a graph is already larger than 
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, because dot on Windows does not 
+# seem to support this out of the box. Warning: Depending on the platform used, 
+# enabling this option may lead to badly anti-aliased labels on the edges of 
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Options related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/QtMeetings.pro b/QtMeetings.pro
new file mode 100644 (file)
index 0000000..38adacb
--- /dev/null
@@ -0,0 +1,132 @@
+TEMPLATE = app
+
+TARGET = qtmeetings
+
+QT += xml \
+    network
+
+INCLUDEPATH += src/Domain/ \
+    src/Domain/Configuration/ \
+    src/IO/ \
+    src/IO/Communication/ \
+    src/IO/DeviceControl/ \
+    src/BusinessLogic/ \
+    src/BusinessLogic/Utils/ \
+    src/UserInterface/ \
+    src/UserInterface/Components/ \
+    src/UserInterface/Utils/ \
+    src/UserInterface/Views/
+
+HEADERS += src/Domain/Room.h \
+    src/Domain/Meeting.h \
+    src/Domain/Configuration/ConnectionSettings.h \
+    src/Domain/Configuration/StartupSettings.h \
+    src/Domain/Configuration/DisplaySettings.h \
+    src/Domain/Configuration/Configuration.h \
+    src/IO/Communication/MessagingUtils.h \
+    src/IO/Communication/Communication.h \
+    src/IO/Communication/CommunicationManager.h \
+    src/IO/DeviceControl/AlarmSender.h \
+    src/IO/DeviceControl/HWKeyListener.h \
+    src/IO/DeviceControl/DeviceDataStorage.h \
+    src/IO/DeviceControl/DeviceConfigurator.h \
+    src/IO/DeviceControl/DeviceManager.h \
+    src/BusinessLogic/Utils/ErrorMapper.h \
+    src/BusinessLogic/Utils/Clock.h \
+    src/BusinessLogic/Engine.h \
+    src/UserInterface/Utils/ToolBox.h \
+    src/UserInterface/Utils/PopUpMessageBox.h \
+    src/UserInterface/Utils/PasswordDialog.h \
+    src/UserInterface/Components/ObservedWidget.h \
+    src/UserInterface/Components/TimeDisplayWidget.h \
+    src/UserInterface/Components/DigitalTimeDisplayWidget.h \
+    src/UserInterface/Components/MeetingRoomCombo.h \
+    src/UserInterface/Components/ScheduleWidget.h \
+    src/UserInterface/Views/RoomStatusIndicatorWidget.h \
+    src/UserInterface/Views/WeeklyViewWidget.h \
+    src/UserInterface/Views/MeetingInfoDialog.h \
+    src/UserInterface/Views/SettingsView.h \
+    src/UserInterface/WindowManager.h
+
+SOURCES += src/Domain/Room.cpp \
+    src/Domain/Meeting.cpp \
+    src/Domain/Configuration/ConnectionSettings.cpp \
+    src/Domain/Configuration/StartupSettings.cpp \
+    src/Domain/Configuration/DisplaySettings.cpp \
+    src/Domain/Configuration/Configuration.cpp \
+    src/IO/Communication/MessagingUtils.cpp \
+    src/IO/Communication/Communication.cpp \
+    src/IO/Communication/CommunicationManager.cpp \
+    src/IO/DeviceControl/AlarmSender.cpp \
+    src/IO/DeviceControl/HWKeyListener.cpp \
+    src/IO/DeviceControl/DeviceDataStorage.cpp \
+    src/IO/DeviceControl/DeviceConfigurator.cpp \
+    src/IO/DeviceControl/DeviceManager.cpp \
+    src/BusinessLogic/Utils/ErrorMapper.cpp \
+    src/BusinessLogic/Utils/Clock.cpp \
+    src/BusinessLogic/Engine.cpp \
+    src/UserInterface/Utils/ToolBox.cpp \
+    src/UserInterface/Utils/PopUpMessageBox.cpp \
+    src/UserInterface/Utils/PasswordDialog.cpp \
+    src/UserInterface/Components/ObservedWidget.cpp \
+    src/UserInterface/Components/TimeDisplayWidget.cpp \
+    src/UserInterface/Components/DigitalTimeDisplayWidget.cpp \
+    src/UserInterface/Components/MeetingRoomCombo.cpp \
+    src/UserInterface/Components/ScheduleWidget.cpp \
+    src/UserInterface/Views/RoomStatusIndicatorWidget.cpp \
+    src/UserInterface/Views/WeeklyViewWidget.cpp \
+    src/UserInterface/Views/MeetingInfoDialog.cpp \
+    src/UserInterface/Views/SettingsView.cpp \
+    src/UserInterface/WindowManager.cpp \
+    src/main.cpp
+
+RESOURCES += resources/BusinessLogic.qrc \
+    resources/UserInterface.qrc
+
+CONFIG += link_pkgconfig
+PKGCONFIG += libalarm
+
+DEFINES += QT_NO_DEBUG_OUTPUT
+
+executable.files = qtmeetings
+executable.path = /usr/bin/
+executable.hint = executable
+INSTALLS += executable
+
+appconfig.files = QtMeetings.conf
+appconfig.path = /etc/
+appconfig.hint = appconfig
+INSTALLS += appconfig
+
+desktop.files = QtMeetings.desktop
+desktop.path = /usr/share/applications/hildon/
+desktop.hint = desktop
+INSTALLS += desktop
+
+devstopperscript.files = scripts/qtmeetings-devstopper
+devstopperscript.path = /usr/bin/
+devstopperscript.hint = devstopperscript
+INSTALLS += devstopperscript
+
+renamescript.files = scripts/qtmeetings-rename
+renamescript.path = /usr/bin/
+renamescript.hint = renamescript
+INSTALLS += renamescript
+
+updatercdscript.files = scripts/qtmeetings-updatercd
+updatercdscript.path = /usr/bin/
+updatercdscript.hint = updatercdscript
+INSTALLS += updatercdscript
+
+launcherscript.files = scripts/qtmeetings-launcher
+launcherscript.path = /etc/init.d/
+launcherscript.hint = launcherscript
+INSTALLS += launcherscript
+
+unix:exists( $$system(which doxygen) ) { 
+    message( "Doxygen is present in your system." )
+    BUILD_NOW = $$prompt( "Do you want to build Doxygen documentation now? [YES/no]" )
+    contains( BUILD_NOW, "YES" ):system( "doxygen QtMeetings.doxygen" )::message( "Documentation is built successfully." )
+}
+else:message( "You must install Doxygen to build the project documentation." )
+message( "Now run 'make' to compile the source code." )
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644 (file)
index 0000000..2e5379e
--- /dev/null
@@ -0,0 +1,6 @@
+qtmeetings for Debian
+---------------------
+
+Qt application to access meeting room's shared calendar on Microsoft Exchange Server 2007, to present availability in customizable weekly or current status view, developed for Nokia N800/810 Internet Tablet.
+
+ -- Ossi Jormakka <ossi.jormakka@ixonos.com>  Thu, 14 May 2009 11:11:00 +0300
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..08cf32a
--- /dev/null
@@ -0,0 +1,44 @@
+qtmeetings (1.0.5-1) unstable; urgency=low
+
+  * Improved communication module for getting a meeting secondary id and detailed information
+  * Improved device control module
+  * Traffic light was showing green light in room status view even if the room was busy
+  * Switched places between the OK and Cancel buttons in PasswordDialog.
+  * Fix for #4061 Meeting info pop up doesn't close with one OK click
+  * Fix for #4068 Room Status View just flashes
+  * Fix for #4062 Error note is not displayed
+  * Fix for #4060 Description and Organizer not shown
+  * Fix for #4063 Traffic lights are truncated
+
+ -- Ossi Jormakka <ossi.jormakka@ixonos.com>  Thu, 14 May 2009 12:30:00 +0300
+
+qtmeetings (1.0.4-1) unstable; urgency=low
+
+  * Improved communication module for handling multiple meeting rooms (one per time)
+  * Improved device control module
+  * Kiosk mode in use
+  * Details of meetings in dialog box
+  * Redesigned Weekly View and Room Status View
+  * Source is fully documented with Doxygen comments
+  * Unit tests are launchable indivudually per classes or all together
+
+ -- Zoltan Papp <zoltan.papp@ixonos.com>  Mon, 4 May 2009 17:15:00 +0000
+
+qtmeetings (1.0.3-3) unstable; urgency=low
+
+  * Configuration path-fix for the previous revision
+
+ -- Zoltan Papp <zoltan.papp@ixonos.com>  Wed, 29 Apr 2009 12:20:00 +0000
+
+qtmeetings (1.0.3-2) unstable; urgency=low
+
+  * Dependency to libalarm-dev added due to failure of compilation in Extras repository
+
+ -- Zoltan Papp <zoltan.papp@ixonos.com>  Tue, 28 Apr 2009 16:00:00 +0000
+
+qtmeetings (1.0.3-1) unstable; urgency=low
+
+  * Initial release 
+
+ -- Zoltan Papp <zoltan.papp@ixonos.com>  Thu, 16 Apr 2009 17:30:00 +0000
+
diff --git a/debian/changelog.Debian b/debian/changelog.Debian
new file mode 100644 (file)
index 0000000..0853ac3
--- /dev/null
@@ -0,0 +1 @@
+for more information see changelog
\ No newline at end of file
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..7ed6ff8
--- /dev/null
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..5f699e8
--- /dev/null
@@ -0,0 +1,13 @@
+Source: qtmeetings
+Section: user/other
+Priority: optional
+Maintainer: Zoltan Papp <zoltan.papp@ixonos.com>
+Build-Depends: debhelper (>= 5), libqt4-dev, libqt4-core, libqt4-gui, libqt4-xml, libqt4-network, libalarm-dev
+Standards-Version: 3.7.2
+
+Package: qtmeetings
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Qt application to access meeting room's shared calendar
+ on Microsoft Exchange Server 2007 developed for Nokia 
+ N800/810 Internet Tablet.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..e66d2fd
--- /dev/null
@@ -0,0 +1,40 @@
+Upstream Author(s):
+
+    Hagman, Jaana <jaana.hagman@ixonos.com>
+    Holopainen, Tanja <tanja.holopainen@ixonos.com>
+    Jokitalo, Janne <janne.jokitalo@ixonos.com>
+    Jormakka, Ossi <ossi.jormakka@ixonos.com>
+    Kasari, Olli <olli.kasari@ixonos.com>
+    Kolehmainen, Mika <mika.kolehmainen@ixonos.com>
+    Kulmala, Miika <miika.kulmala@ixonos.com>
+    Kupari, Teemu <teemu.kupari@ixonos.com>
+    Lapinkataja, Jan <jan.lapinkataja@ixonos.com>
+    Maslova, Ugne <ugne.maslova@ixonos.com>
+    Ollenberg, Aki <aki.ollenberg@ixonos.com>
+    Papp, Zoltan <zoltan.papp@ixonos.com>
+    Riihola, Juha <juha.riihola@ixonos.com>
+    Sihvo, Jouni <jouni.sihvo@ixonos.com>
+    Sirén, Mikko <mikko.siren@ixonos.com>
+
+Copyright:
+
+    Copyright (C) 2009  Ixonos Plc.
+
+License:
+
+    This package 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 2 of the License, or
+    (at your option) any later version.
+
+    This package 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 package; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+    On Debian systems, the complete text of the GNU General
+    Public License can be found in `/usr/share/common-licenses/GPL'.
diff --git a/debian/postinst b/debian/postinst
new file mode 100644 (file)
index 0000000..a729807
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+set -e
+
+maemo-select-menu-location QtMeetings.desktop
+
+exit 0
\ No newline at end of file
diff --git a/debian/postrm b/debian/postrm
new file mode 100644 (file)
index 0000000..00ece1c
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+set -e
+
+#  Check that /etc/sudoers file exists
+if [ -e /etc/sudoers ]; then
+       grep -v 'qtmeetings' /etc/sudoers > /tmp/sudoers.new
+       cp /tmp/sudoers.new /etc/sudoers
+       rm /tmp/sudoers.new
+fi
+
+if [ -e /usr/bin/qtmeetings-rename ]; then
+       rm /usr/bin/qtmeetings-rename
+fi
+
+if [ -e /usr/bin/qtmeetings-devstopper ]; then
+       rm /usr/bin/qtmeetings-devstopper
+fi
+
+if [ -e /usr/bin/qtmeetings-updatercd ]; then
+       rm /usr/bin/qtmeetings-updatercd
+fi     
+
+if [ -e /usr/var/qtmeetings.txt ]; then
+       rm /usr/var/qtmeetings.txt
+fi
+
+exit 0
diff --git a/debian/preinst b/debian/preinst
new file mode 100644 (file)
index 0000000..06b7504
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+set -e
+
+#  Check that /etc/sudoers file exists
+if [ ! -e /etc/sudoers ]; then
+       echo "Error: No /etc/sudoers file. Is sudo installed ?" 
+       exit 1
+fi
+
+if ( ! grep qtmeetings-updatercd /etc/sudoers 2>/dev/null >/dev/null ); then
+       echo 'user ALL = NOPASSWD: /usr/bin/qtmeetings-updatercd' >> /etc/sudoers
+fi
+
+if ( ! grep qtmeetings-rename /etc/sudoers 2>/dev/null >/dev/null ); then
+       echo 'user ALL = NOPASSWD: /usr/bin/qtmeetings-rename' >> /etc/sudoers
+fi
+
+exit 0
\ No newline at end of file
diff --git a/debian/qtmeetings.install b/debian/qtmeetings.install
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/debian/qtmeetings/DEBIAN/conffiles b/debian/qtmeetings/DEBIAN/conffiles
new file mode 100644 (file)
index 0000000..d97a05d
--- /dev/null
@@ -0,0 +1,2 @@
+/etc/init.d/qtmeetings-launcher
+/etc/QtMeetings.conf
diff --git a/debian/qtmeetings/DEBIAN/control b/debian/qtmeetings/DEBIAN/control
new file mode 100644 (file)
index 0000000..72b4cfb
--- /dev/null
@@ -0,0 +1,11 @@
+Package: qtmeetings
+Version: 1.0.5-1
+Section: user/other
+Priority: optional
+Architecture: armel
+Depends: libalarm0 (>= 0.5.20), libc6 (>= 2.5.0-1), libgcc1 (>= 1:3.4.4), libqt4-network (>= 4.4.0), libqt4-xml (>= 4.4.0), libqtcore4 (>= 4.4.0), libqtgui4 (>= 4.4.0), libstdc++6 (>= 3.4.4)
+Installed-Size: 660
+Maintainer: Zoltan Papp <zoltan.papp@ixonos.com>
+Description: Qt application to access meeting room's shared calendar
+ on Microsoft Exchange Server 2007 developed for Nokia
+ N800/810 Internet Tablet.
diff --git a/debian/qtmeetings/DEBIAN/md5sums b/debian/qtmeetings/DEBIAN/md5sums
new file mode 100644 (file)
index 0000000..479426b
--- /dev/null
@@ -0,0 +1,7 @@
+24d4fabbf8f62ef25a57769182b6417e  usr/share/doc/qtmeetings/README.Debian
+7895482ea907cf53dab85a4543e838f5  usr/share/doc/qtmeetings/copyright
+62db04cd3c8d12c924158af250a0d2df  usr/share/applications/hildon/QtMeetings.desktop
+3491e49963a41b9b27e27ead4e6d559b  usr/bin/qtmeetings-devstopper
+bbfd6c68e82075825bf439c6834e20c4  usr/bin/qtmeetings
+2d402ba0e905291c6c5ac0d4efe4d519  usr/bin/qtmeetings-updatercd
+ad0a015d12de590f84f7d955255b9c1e  usr/bin/qtmeetings-rename
diff --git a/debian/qtmeetings/DEBIAN/postinst b/debian/qtmeetings/DEBIAN/postinst
new file mode 100755 (executable)
index 0000000..a729807
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+set -e
+
+maemo-select-menu-location QtMeetings.desktop
+
+exit 0
\ No newline at end of file
diff --git a/debian/qtmeetings/DEBIAN/postrm b/debian/qtmeetings/DEBIAN/postrm
new file mode 100755 (executable)
index 0000000..00ece1c
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+set -e
+
+#  Check that /etc/sudoers file exists
+if [ -e /etc/sudoers ]; then
+       grep -v 'qtmeetings' /etc/sudoers > /tmp/sudoers.new
+       cp /tmp/sudoers.new /etc/sudoers
+       rm /tmp/sudoers.new
+fi
+
+if [ -e /usr/bin/qtmeetings-rename ]; then
+       rm /usr/bin/qtmeetings-rename
+fi
+
+if [ -e /usr/bin/qtmeetings-devstopper ]; then
+       rm /usr/bin/qtmeetings-devstopper
+fi
+
+if [ -e /usr/bin/qtmeetings-updatercd ]; then
+       rm /usr/bin/qtmeetings-updatercd
+fi     
+
+if [ -e /usr/var/qtmeetings.txt ]; then
+       rm /usr/var/qtmeetings.txt
+fi
+
+exit 0
diff --git a/debian/qtmeetings/DEBIAN/preinst b/debian/qtmeetings/DEBIAN/preinst
new file mode 100755 (executable)
index 0000000..06b7504
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+set -e
+
+#  Check that /etc/sudoers file exists
+if [ ! -e /etc/sudoers ]; then
+       echo "Error: No /etc/sudoers file. Is sudo installed ?" 
+       exit 1
+fi
+
+if ( ! grep qtmeetings-updatercd /etc/sudoers 2>/dev/null >/dev/null ); then
+       echo 'user ALL = NOPASSWD: /usr/bin/qtmeetings-updatercd' >> /etc/sudoers
+fi
+
+if ( ! grep qtmeetings-rename /etc/sudoers 2>/dev/null >/dev/null ); then
+       echo 'user ALL = NOPASSWD: /usr/bin/qtmeetings-rename' >> /etc/sudoers
+fi
+
+exit 0
\ No newline at end of file
diff --git a/debian/qtmeetings/etc/QtMeetings.conf b/debian/qtmeetings/etc/QtMeetings.conf
new file mode 100644 (file)
index 0000000..7066087
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration password="admin" >
+
+       <connection>
+               <!-- TEST SERVER DATA-->
+               <!--<serverurl>192.168.0.35</serverurl>
+               <username>maemo</username>
+               <password>P@ssw0rd</password>-->
+               <serverurl>jklexch01.ixonos.com</serverurl>
+               <username></username>
+               <password></password>
+               <!-- interval is interpreted in seconds -->
+               <refreshinterval>60</refreshinterval>
+       </connection>
+
+       <startup>
+               <powersaving enabled="true" on="08:00" off="17:00" />
+       </startup>
+
+       <display>
+               <!-- only 5 or 7 days-long weeks are supported -->
+               <schedule>
+                       <week days="5" />
+                       <day startsat="08:00" endsat="17:00" />
+               </schedule>
+               <!-- date and time format strings must be compatible with Qt's QDateTime formatting  -->
+               <dateformat>ddd dd MMM</dateformat>
+               <timeformat>hh:mm</timeformat>
+       </display>
+
+    <rooms>
+               <!-- TEST SERVER DEFAULT ROOM
+               DO NOT FODGET TO DELETE THE DEFAULT="TRUE" ATTRIBUTE OF TAURUS
+               -->
+               <room>
+                       <name>TestRoom</name>
+                       <address>meetingroomtest@test.local</address>
+               </room>
+               
+               <room>
+                       <name>Pegasus</name>
+                       <address>meetingroom.pegasus_jyv@ixonos.com</address>
+               </room>
+               <room default="true">
+                       <name>Taurus</name>
+                       <address>meetingroom.taurus_jyv@ixonos.com</address>
+               </room>
+               <room>
+                       <name>Hercules</name>
+                       <address>meetingroom.hercules@ixonos.com</address>
+               </room>
+       </rooms>
+
+       <!-- language code must be in ISO 3166-1 alpha-2 standard -->
+       <language code="EN" />
+
+</configuration>
diff --git a/debian/qtmeetings/etc/init.d/qtmeetings-launcher b/debian/qtmeetings/etc/init.d/qtmeetings-launcher
new file mode 100755 (executable)
index 0000000..7645f9b
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+# must be in /etc/init.d/
+
+case "$1" in
+       start)
+       test -x $PROG || exit 0
+       export DISPLAY=':0.0'
+       cd /usr/bin/
+       run-standalone.sh /usr/bin/qtmeetings &
+       ;;
+       *)
+           exit 1
+       ;;
+esac
+
diff --git a/debian/qtmeetings/usr/bin/qtmeetings b/debian/qtmeetings/usr/bin/qtmeetings
new file mode 100755 (executable)
index 0000000..a7ebed1
Binary files /dev/null and b/debian/qtmeetings/usr/bin/qtmeetings differ
diff --git a/debian/qtmeetings/usr/bin/qtmeetings-devstopper b/debian/qtmeetings/usr/bin/qtmeetings-devstopper
new file mode 100755 (executable)
index 0000000..e692f6c
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# must be in /usr/bin/
+
+case "$1" in
+   restart)
+      SUFFIX=req_reboot
+      ;;
+   *)
+      SUFFIX=req_shutdown
+      ;;
+esac
+
+run-standalone.sh dbus-send --system --type=method_call --dest='com.nokia.mce' --print-reply '/com/nokia/mce/request' com.nokia.mce.request.$SUFFIX
diff --git a/debian/qtmeetings/usr/bin/qtmeetings-rename b/debian/qtmeetings/usr/bin/qtmeetings-rename
new file mode 100755 (executable)
index 0000000..19b525c
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# must be in /usr/bin/
+
+if [ -e $1 ]; then
+    mv $1 $2
+fi
diff --git a/debian/qtmeetings/usr/bin/qtmeetings-updatercd b/debian/qtmeetings/usr/bin/qtmeetings-updatercd
new file mode 100755 (executable)
index 0000000..50a2d4f
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+# must be in /usr/bin/
+
+case "$1" in
+       install)
+               update-rc.d qtmeetings-launcher start 99 2
+               ;;
+       remove)
+               update-rc.d -f qtmeetings-launcher remove
+               ;;
+       *)
+               exit 0
+               ;;
+esac
diff --git a/debian/qtmeetings/usr/share/applications/hildon/QtMeetings.desktop b/debian/qtmeetings/usr/share/applications/hildon/QtMeetings.desktop
new file mode 100644 (file)
index 0000000..c5c0587
--- /dev/null
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Encoding=UTF-8
+Version=1.0.3
+Type=Application
+Name=Qt Meetings
+Comment=Qt application to access meeting room's shared calendar.
+Exec=/usr/bin/qtmeetings
+Icon=qtmeetings
+X-HildonDesk-ShowInToolbar=true
+#X-Osso-Service=qtmeetings_app
+X-Osso-Type=application/x-executable
+Teminal=false
\ No newline at end of file
diff --git a/debian/qtmeetings/usr/share/doc/qtmeetings/README.Debian b/debian/qtmeetings/usr/share/doc/qtmeetings/README.Debian
new file mode 100644 (file)
index 0000000..2e5379e
--- /dev/null
@@ -0,0 +1,6 @@
+qtmeetings for Debian
+---------------------
+
+Qt application to access meeting room's shared calendar on Microsoft Exchange Server 2007, to present availability in customizable weekly or current status view, developed for Nokia N800/810 Internet Tablet.
+
+ -- Ossi Jormakka <ossi.jormakka@ixonos.com>  Thu, 14 May 2009 11:11:00 +0300
diff --git a/debian/qtmeetings/usr/share/doc/qtmeetings/copyright b/debian/qtmeetings/usr/share/doc/qtmeetings/copyright
new file mode 100644 (file)
index 0000000..e66d2fd
--- /dev/null
@@ -0,0 +1,40 @@
+Upstream Author(s):
+
+    Hagman, Jaana <jaana.hagman@ixonos.com>
+    Holopainen, Tanja <tanja.holopainen@ixonos.com>
+    Jokitalo, Janne <janne.jokitalo@ixonos.com>
+    Jormakka, Ossi <ossi.jormakka@ixonos.com>
+    Kasari, Olli <olli.kasari@ixonos.com>
+    Kolehmainen, Mika <mika.kolehmainen@ixonos.com>
+    Kulmala, Miika <miika.kulmala@ixonos.com>
+    Kupari, Teemu <teemu.kupari@ixonos.com>
+    Lapinkataja, Jan <jan.lapinkataja@ixonos.com>
+    Maslova, Ugne <ugne.maslova@ixonos.com>
+    Ollenberg, Aki <aki.ollenberg@ixonos.com>
+    Papp, Zoltan <zoltan.papp@ixonos.com>
+    Riihola, Juha <juha.riihola@ixonos.com>
+    Sihvo, Jouni <jouni.sihvo@ixonos.com>
+    Sirén, Mikko <mikko.siren@ixonos.com>
+
+Copyright:
+
+    Copyright (C) 2009  Ixonos Plc.
+
+License:
+
+    This package 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 2 of the License, or
+    (at your option) any later version.
+
+    This package 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 package; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+    On Debian systems, the complete text of the GNU General
+    Public License can be found in `/usr/share/common-licenses/GPL'.
diff --git a/debian/rules b/debian/rules
new file mode 100644 (file)
index 0000000..5a34552
--- /dev/null
@@ -0,0 +1,78 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+export DH_VERBOSE=1
+APPNAME := QtMeetings
+SCND_NAME := qtmeetings
+builddir:
+       mkdir -p builddir
+
+builddir/Makefile: builddir
+       cd builddir && qmake-qt4 PREFIX=/usr ../$(APPNAME).pro
+
+build: build-stamp
+
+build-stamp: builddir/Makefile
+       dh_testdir
+       # Add here commands to compile the package.
+       cd builddir && $(MAKE)
+       touch $@
+clean:
+       dh_testdir
+       dh_testroot
+       rm -f build-stamp
+       # Add here commands to clean up after the build process.
+       rm -rf builddir
+       dh_clean
+install: build
+       dh_testdir
+       dh_testroot
+       dh_clean -k 
+       dh_installdirs
+
+       # Add here commands to install the package into debian/ixonosmeetings.
+       cd builddir && $(MAKE) INSTALL_ROOT=$(CURDIR)/debian/$(SCND_NAME) install
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+       dh_testdir
+       dh_testroot
+#      dh_installchangelogs 
+       dh_installdocs
+       dh_installexamples
+       dh_install
+#      dh_installmenu
+#      dh_installdebconf       
+#      dh_installlogrotate
+#      dh_installemacsen
+#      dh_installpam
+#      dh_installmime
+#      dh_python
+#      dh_installinit
+#      dh_installcron
+#      dh_installinfo
+       dh_installman
+       dh_link
+       dh_strip
+       dh_compress
+       dh_fixperms
+#      dh_perl
+#      dh_makeshlibs
+       dh_installdeb
+       dh_shlibdeps
+       dh_gencontrol
+       dh_md5sums
+       dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
diff --git a/resources/BusinessLogic.qrc b/resources/BusinessLogic.qrc
new file mode 100644 (file)
index 0000000..0f7a535
--- /dev/null
@@ -0,0 +1,5 @@
+<RCC>\r
+<qresource prefix="/" >\r
+   <file alias="errortable" >xml/errortable.xml</file>\r
+</qresource>\r
+</RCC>\r
diff --git a/resources/UserInterface.qrc b/resources/UserInterface.qrc
new file mode 100644 (file)
index 0000000..dc3301b
--- /dev/null
@@ -0,0 +1,16 @@
+<RCC>
+    <qresource prefix="/" >
+        <file alias="arrow_left" >icons/arrow_left.png</file>
+        <file alias="arrow_right" >icons/arrow_right.png</file>
+        <file alias="button_current" >icons/button_current.png</file>
+        <file alias="button_settings" >icons/button_settings.png</file>
+        <file alias="roomstatus_busy" >icons/roomstatus_busy.png</file>
+        <file alias="roomstatus_free" >icons/roomstatus_free.png</file>
+        <file alias="popup_cancel" >icons/popup_cancel.png</file>
+        <file alias="popup_error" >icons/popup_error.png</file>
+        <file alias="popup_information" >icons/popup_information.png</file>
+        <file alias="popup_ok" >icons/popup_ok.png</file>
+        <file alias="popup_question" >icons/popup_question.png</file>
+        <file alias="popup_warning" >icons/popup_warning.png</file>
+    </qresource>
+</RCC>
diff --git a/resources/icons/arrow_left.png b/resources/icons/arrow_left.png
new file mode 100644 (file)
index 0000000..0b7273c
Binary files /dev/null and b/resources/icons/arrow_left.png differ
diff --git a/resources/icons/arrow_right.png b/resources/icons/arrow_right.png
new file mode 100644 (file)
index 0000000..859bcad
Binary files /dev/null and b/resources/icons/arrow_right.png differ
diff --git a/resources/icons/button_current.png b/resources/icons/button_current.png
new file mode 100644 (file)
index 0000000..6df4087
Binary files /dev/null and b/resources/icons/button_current.png differ
diff --git a/resources/icons/button_settings.png b/resources/icons/button_settings.png
new file mode 100644 (file)
index 0000000..682d311
Binary files /dev/null and b/resources/icons/button_settings.png differ
diff --git a/resources/icons/popup_cancel.png b/resources/icons/popup_cancel.png
new file mode 100644 (file)
index 0000000..2c9d6df
Binary files /dev/null and b/resources/icons/popup_cancel.png differ
diff --git a/resources/icons/popup_error.png b/resources/icons/popup_error.png
new file mode 100644 (file)
index 0000000..900f9c7
Binary files /dev/null and b/resources/icons/popup_error.png differ
diff --git a/resources/icons/popup_information.png b/resources/icons/popup_information.png
new file mode 100644 (file)
index 0000000..4865991
Binary files /dev/null and b/resources/icons/popup_information.png differ
diff --git a/resources/icons/popup_ok.png b/resources/icons/popup_ok.png
new file mode 100644 (file)
index 0000000..37b1d3a
Binary files /dev/null and b/resources/icons/popup_ok.png differ
diff --git a/resources/icons/popup_question.png b/resources/icons/popup_question.png
new file mode 100644 (file)
index 0000000..b91d139
Binary files /dev/null and b/resources/icons/popup_question.png differ
diff --git a/resources/icons/popup_warning.png b/resources/icons/popup_warning.png
new file mode 100644 (file)
index 0000000..46edc41
Binary files /dev/null and b/resources/icons/popup_warning.png differ
diff --git a/resources/icons/roomstatus_busy.png b/resources/icons/roomstatus_busy.png
new file mode 100644 (file)
index 0000000..d735440
Binary files /dev/null and b/resources/icons/roomstatus_busy.png differ
diff --git a/resources/icons/roomstatus_free.png b/resources/icons/roomstatus_free.png
new file mode 100644 (file)
index 0000000..14aa52f
Binary files /dev/null and b/resources/icons/roomstatus_free.png differ
diff --git a/resources/xml/errortable.xml b/resources/xml/errortable.xml
new file mode 100644 (file)
index 0000000..d611fda
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<errors>
+    <error code="0">Not really an error. Everything went just fine.</error>
+    <error code="666">For unit test purposes.</error>
+    <error code="100">Communication: No Error</error>
+    <error code="101">Communication: Unknown error</error>
+    <error code="102">Communication: Host name lookup failed</error>
+    <error code="103">Communication: Server refused the connection</error>
+    <error code="104">Communication: Server closed the connection unexpectedly</error>
+    <error code="105">Communication: Server sent an invalid HTTP header</error>
+    <error code="106">Communication: Server sent an invalid content length</error>
+    <error code="107">Communication: Invalid username or password</error>
+    <error code="108">Communication: SOAP error when fetching meetings</error>
+    <error code="109">Communication: SOAP error when fetching meeting details</error>
+    <error code="110">Communication error</error>
+    <error code="200">Failed to change the operation mode. Error creating internal file storage.</error>
+    <error code="201">Failed to change the operation mode. Error removing old alarm events.</error>
+       <error code="202">Failed to change the operation mode. Error sending alarm events. %1</error>
+       <error code="203">Failed to change the operation mode. Error storing data about sent alarm events. Removing the already sent alarm events.</error>
+       <error code="204">Failed to change the operation mode. Error fetching data of original hardware key settings.</error>
+       <error code="205">Failed to change the operation mode. Error storing data of original hardware key settings.</error>
+       <error code="206">Failed to change the operation mode. Error changing hardware key settings.</error>
+       <error code="207">Failed to change the operation mode. Init script to auto launch the application was not installed/removed.</error>
+       <error code="208">Failed to change the operation mode. The application failed to know the current mode of itself.</error>
+       <error code="209">Failed to change the operation mode. The application failed to store the current mode of itself.</error>
+       <error code="210">Error storing data of original automatic screen switching-off and dimming parameter values. Using the default values instead.</error>
+       <error code="211">Error fetching data of original automatic screen switching-off and dimming parameter values. Using the default values instead.</error>
+       <error code="212">Failed to change the operation mode. Error changing automatic screen switching-off and dimming parameter values.</error>
+       <error code="213">Failed to change the operation mode. Error restarting the device.</error>
+</errors>
diff --git a/scripts/qtmeetings-devstopper b/scripts/qtmeetings-devstopper
new file mode 100755 (executable)
index 0000000..e692f6c
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+# must be in /usr/bin/
+
+case "$1" in
+   restart)
+      SUFFIX=req_reboot
+      ;;
+   *)
+      SUFFIX=req_shutdown
+      ;;
+esac
+
+run-standalone.sh dbus-send --system --type=method_call --dest='com.nokia.mce' --print-reply '/com/nokia/mce/request' com.nokia.mce.request.$SUFFIX
diff --git a/scripts/qtmeetings-launcher b/scripts/qtmeetings-launcher
new file mode 100755 (executable)
index 0000000..7645f9b
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+# must be in /etc/init.d/
+
+case "$1" in
+       start)
+       test -x $PROG || exit 0
+       export DISPLAY=':0.0'
+       cd /usr/bin/
+       run-standalone.sh /usr/bin/qtmeetings &
+       ;;
+       *)
+           exit 1
+       ;;
+esac
+
diff --git a/scripts/qtmeetings-rename b/scripts/qtmeetings-rename
new file mode 100755 (executable)
index 0000000..19b525c
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+# must be in /usr/bin/
+
+if [ -e $1 ]; then
+    mv $1 $2
+fi
diff --git a/scripts/qtmeetings-updatercd b/scripts/qtmeetings-updatercd
new file mode 100755 (executable)
index 0000000..50a2d4f
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+# must be in /usr/bin/
+
+case "$1" in
+       install)
+               update-rc.d qtmeetings-launcher start 99 2
+               ;;
+       remove)
+               update-rc.d -f qtmeetings-launcher remove
+               ;;
+       *)
+               exit 0
+               ;;
+esac
diff --git a/src/BusinessLogic/Engine.cpp b/src/BusinessLogic/Engine.cpp
new file mode 100644 (file)
index 0000000..2f943a7
--- /dev/null
@@ -0,0 +1,241 @@
+#include "Engine.h"
+
+#include <QTimer>
+#include <QList>
+#include "Room.h"
+#include "Meeting.h"
+#include "ConnectionSettings.h"
+#include "Configuration.h"
+#include "CommunicationManager.h"
+#include "DeviceManager.h"
+#include "Clock.h"
+#include "ErrorMapper.h"
+
+#include <QtDebug>
+
+QTime Engine::endOfTheDay = QTime( 23, 59, 0, 0 ); // end of the day is 11:59pm
+
+Engine::Engine() :
+               iClock( 0 ), iConfiguration( Configuration::instance() ), iCommunication( 0 ), iCurrentRoom( 0 )
+{
+       // if reading of configuration fails, signal that initialization failed
+       if ( iConfiguration == 0 )
+       {
+               QTimer::singleShot( 0, this, SIGNAL( initializationFailed() ) );
+               return;
+       }
+       // initialize communication
+       iCommunication = new CommunicationManager( *(iConfiguration->connectionSettings()) );
+       connect( iCommunication,
+                        SIGNAL( error( int, CommunicationManager::CommunicationType  ) ),
+                        this,
+                        SLOT( errorHandler( int ) ) );
+       connect( iCommunication,
+                        SIGNAL( meetingsFetched( const QList<Meeting*>& ) ),
+                        this,
+                        SLOT( meetingsFetched( const QList<Meeting*>& ) )
+                       );
+       connect( iCommunication,
+                        SIGNAL( meetingDetailsFetched( Meeting& ) ),
+                        this,
+                        SLOT( meetingDetailsFetched( Meeting& ) )
+                       );
+
+       // create application clock
+       iClock = new Clock;
+       connect( iClock, SIGNAL( tick( QDateTime ) ), this, SLOT( checkStatusOfAllRooms() ) );
+
+       iAutoRefresh = new QTimer;
+       iAutoRefresh->setInterval( iConfiguration->connectionSettings()->refreshInterval() * 1000 );
+       iAutoRefresh->start();
+       connect( iAutoRefresh, SIGNAL( timeout() ), iAutoRefresh, SLOT( start() ) );
+       connect( iAutoRefresh, SIGNAL( timeout() ), this, SLOT( fetchMeetings() ) );
+
+       iDevice = new DeviceManager( iConfiguration->startupSettings() );
+       connect( iDevice, SIGNAL( error( int, const QString& ) ), this, SLOT( errorHandler( int, const QString& ) ) );
+       iDevice->initDeviceManager();
+
+       QTimer::singleShot( 0, this, SLOT( fetchMeetings() ) );
+
+       // TODO: continue implementation
+}
+
+Engine::~Engine()
+{
+       while ( !iMeetings.isEmpty() )
+               delete iMeetings.takeFirst();
+}
+
+Room* Engine::defaultRoom()
+{
+       return iConfiguration->defaultRoom();
+}
+
+Clock* Engine::clock()
+{
+       return iClock;
+}
+
+Configuration* Engine::configuration()
+{
+       return iConfiguration;
+}
+
+DeviceManager* Engine::deviceManager()
+{
+       return iDevice;
+}
+
+void Engine::checkStatusOfAllRooms()
+{
+       // iterate trough on the rooms
+       for ( int i = 0; i < iConfiguration->rooms().count(); i++ )
+       {
+               // and check the status
+               roomStatusInfoNeeded( iConfiguration->rooms().at( i ) );
+       }
+}
+
+int Engine::indexOfMeetingAt( Room *aRoom, QDateTime aAt )
+{
+       for ( int i = 0; i < iMeetings.count(); i++ )
+       {
+               // exchange server ensures that there is only one meeting in a room at a specified time
+               if ( aRoom->equals( iMeetings.at( i )->room() )
+                         && iMeetings.at( i )->startsAt() <= aAt
+                         && iMeetings.at( i )->endsAt() >= aAt )
+               {
+                       return i;
+               }
+       }
+       return -1;
+}
+
+int Engine::indexOfMeetingAfter( Room *aRoom, QDateTime aAfter )
+{
+       // seeks for the next meeting on the SAME DAY
+       int min = -1;
+       for ( int i = 0; i < iMeetings.count(); i++ )
+       {
+               // if the meeting is in the same room, on the same day but after the specified time
+               if ( aRoom->equals( iMeetings.at( i )->room() )
+                         && iMeetings.at( i )->startsAt().date() == aAfter.date()
+                         && iMeetings.at( i )->startsAt() > aAfter )
+               {
+                       // if there was not any meeting find yet or the previously found is a later one then the (i)th
+                       if ( min == -1
+                                 || iMeetings.at( min )->startsAt() > iMeetings.at( i )->startsAt() )
+                       {
+                               min = i;
+                       }
+               }
+       }
+       return min;
+}
+
+void Engine::roomStatusInfoNeeded( Room *aRoom )
+{
+       if ( aRoom == 0 )
+       {
+               return;
+       }
+
+       int indexOfCurrentMeeting = indexOfMeetingAt( aRoom, iClock->datetime() );
+       int indexOfNextMeeting = indexOfMeetingAfter( aRoom, iClock->datetime() );
+
+//     qDebug() << QString( "Engine::roomStatusInfoNeeded\troom:%1current:%2 next:%3" ).arg( aRoom->toString() ).arg( indexOfCurrentMeeting ).arg( indexOfNextMeeting );
+
+       // if there is no meeting, then status is Free; otherwise Busy
+       Room::Status status = ( indexOfCurrentMeeting == -1 ) ? Room::FreeStatus : Room::BusyStatus;
+       // if room is Busy, then check end time, otherwise...
+       QTime until = ( status == Room::BusyStatus ) ? iMeetings.at( indexOfCurrentMeeting )->endsAt().time() :
+                         // ...if there is meeting following on the same day then check end time, otherwise end is the of the working day
+                         (( indexOfNextMeeting != -1 ) ? iMeetings.at( indexOfNextMeeting )->startsAt().time() : Engine::endOfTheDay );
+
+       emit roomStatusChanged( aRoom, status, until );
+}
+
+void Engine::fetchMeetings()
+{
+       // TODO : define interval correctly. at the moment it's +/- 14 days
+       Room *room = iCurrentRoom;
+       if ( room == 0 ) room = defaultRoom();
+       qDebug() << "Engine::fetchMeetings for " << room->name();
+       fetchMeetings( iClock->datetime().addDays( -14 ), iClock->datetime().addDays( 14 ), room );
+}
+
+void Engine::fetchMeetings( const QDateTime &aFrom, const QDateTime &aUntil, Room *aIn )
+{
+       iCommunication->fetchMeetings( aFrom, aUntil, *aIn );
+}
+
+void Engine::fetchMeetingDetails( Meeting *aMeeting )
+{
+       iCommunication->fetchMeetingDetails( *aMeeting );
+}
+
+bool Engine::isMeetingInList( const QList<Meeting*> &aList, const Meeting *aMeeting )
+{
+       for ( int i = 0; i < aList.count(); i++ )
+       {
+               if ( aMeeting->equals( *(aList.at( i )) ) )
+               {
+                       return true;
+               }
+       }
+       return false;
+}
+
+void Engine::meetingsFetched( const QList<Meeting*> &aMeetings )
+{
+       // check if there is any new meeting in the list came from the server -> added
+       for ( int i = 0; i < aMeetings.count(); i++ )
+       {
+               // if the (i)th meeting is not in the local meeting list
+               if ( !isMeetingInList( iMeetings, aMeetings.at( i ) ) )
+               {
+                       // add to the local database =)
+                       Meeting* m = new Meeting( *(aMeetings.at( i )) );
+                       iMeetings.append( m );
+                       // and signal the changes
+                       emit meetingAdded( m );
+               }
+       }
+
+       // check if there is any meeting NOT in the list came from the server -> deleted
+       for ( int i = 0; i < iMeetings.count(); i++ )
+       {
+               // if the (i)th meeting is in the local but NOT in the server's meeting list
+               if ( !isMeetingInList( aMeetings, iMeetings.at( i ) ) )
+               {
+                       Meeting* m = iMeetings.takeAt( i );
+                       // signal the changes
+                       emit meetingDeleted( m );
+                       // delete the meeting from the local list
+                       delete m;
+               }
+       }
+
+       // refresh room status info
+       roomStatusInfoNeeded( defaultRoom() );
+}
+
+void Engine::meetingDetailsFetched( Meeting &aDetailedMeeting )
+{
+       emit meetingDetailsFetched( &aDetailedMeeting );
+}
+
+void Engine::errorHandler( int aCode, const QString &aAddInfo )
+{
+       qDebug() << "Engine::ErrorHandler, aCode: " << aCode;
+       // inform UI about the problem
+       if( aCode >= 100 && aCode <= 110 )
+               qDebug() << "CommunicationManager signaled an error:" << aCode;
+       emit error( ErrorMapper::codeToString( aCode, aAddInfo ) );
+}
+
+void Engine::currentRoomChanged( Room *aCurrentRoom )
+{
+       iCurrentRoom = aCurrentRoom;
+       qDebug() << "Engine::currentRoomChanged to " << iCurrentRoom->name();
+}
diff --git a/src/BusinessLogic/Engine.h b/src/BusinessLogic/Engine.h
new file mode 100644 (file)
index 0000000..47b2a4d
--- /dev/null
@@ -0,0 +1,195 @@
+#ifndef ENGINE_H_
+#define ENGINE_H_
+
+#include <QObject>
+#include <QDateTime>
+#include "Room.h"
+
+class QTimer;
+class Clock;
+class Configuration;
+class CommunicationManager;
+class Meeting;
+class DeviceManager;
+
+//! BusinessLogic class. Contains all the business logic of the application.
+/*!
+ * BusinessLogic class. Contains all the business logic of the application. It is responsible
+ * for connecting user interface to lower application layers (IO).
+ */
+class Engine : public QObject
+{
+       Q_OBJECT
+
+public:
+       //! Constructor.
+       /*!
+        * Constructor to initialize an Engine instance.
+        */
+       Engine();
+       //! Destructor.
+       virtual ~Engine();
+
+       //! Gets the clock instance used by the object to get up-to-date date and time info.
+       /*!
+        * Gets the clock instance used by the object to get up-to-date date and time info.
+        * \return Pointer to the Clock instance.
+        */
+       Clock* clock();
+       //! Gets the application's configuration.
+       /*!
+        * Gets the application's configuration.
+        * \return Pointer to the Configuration instance.
+        */
+       Configuration* configuration();
+       //! Gets default room of the application.
+       /*!
+        * Gets default room of the application.
+        * \return Pointer to the default Room instance.
+        */
+       Room* defaultRoom();
+       //! Gets the deviceManager instance
+       /*!
+        * Gets the deviceManager instance.
+        * \return Pointer to the deviceManager instance.
+        */
+       DeviceManager* deviceManager();
+
+signals:
+       //! Signal. Emitted if initialization of the current instance failed.
+       /*!
+        * Signal. Emitted if initialization of the current instance failed, if reading of the configuration
+        * was not successful. It's purpose to inform the userinterface that the Engine is not ready for
+        * controlling the application, application must be shut down.
+        */
+       void initializationFailed();
+       //! Signal. Emitted if the availability information of the specified room changed.
+       /*!
+        * Signal. Emitted if the availability information of the specified room changed.
+        * \param aRoom The Room instance which availability changed.
+        * \param aStatus The status of the room.
+        * \param aUntil Time until the spacified status is valid.
+        */
+       void roomStatusChanged( Room *aRoom, Room::Status aStatus, QTime aUntil );
+       //! Signal. Emitted if new meeting was found on the server.
+       /*!
+        * Signal. Emitted if new meeting was found on the server.
+        * \param aMeeting The new meeting which was added.
+        */
+       void meetingAdded( Meeting *aMeeting );
+       //! Signal. Emitted if meeting was deleted on the server.
+       /*!
+        * Signal. Emitted if meeting was deleted on the server.
+        * \param aMeeting The meeting which was deleted.
+        */
+       void meetingDeleted( Meeting *aMeeting );
+       //! Signal. Emitted error occured and error message must be shown on UI.
+       /*!
+        * Signal. Emitted error occured and error message must be shown on UI.
+        * \param aErrorMessage The message.
+        */
+       void error( const QString &aErrorMessage );
+
+       void meetingDetailsFetched( Meeting *aDetailedMeeting );
+
+public slots:
+       //! Slot. Checks actual availability information of the specified room.
+       /*!
+        * Slot. Checks actual availability information of the specified room.
+        * \param aRoom The room which availability information is needed.
+        */
+       void roomStatusInfoNeeded( Room *aRoom );
+       //! Slot. Fetches meetings from the server.
+       /*!
+        * Slot. Fetches meetings from the server, exact parameters are specified in the parameter list.
+        * \param aFrom Time from when the meetings need to be fetched.
+        * \param aUntil Time until when the meetings need to be fetched.
+        * \param aIn The room which meetings need to be fetched.
+        */
+       void fetchMeetings( const QDateTime &aFrom, const QDateTime &aUntil, Room *aIn );
+       
+       void fetchMeetingDetails( Meeting * );
+       
+       /*!
+        * Slot. Sets the current meeting room iCurrentRoom.
+        * \param aCurrentRoom
+        */
+       void currentRoomChanged( Room *aCurrentRoom );
+
+private slots:
+       //! Slot. Handles errors.
+       /*!
+        * Slot. Handles errors and informs the UI by emitting the error() signal with the message in
+        * parameter.
+        * \param aCode The error code.
+        * \param aAddInfo Possible addition info.
+        */
+       void errorHandler( int aCode, const QString &aAddInfo = "" );
+       //! Slot. Fetches meetings from the server.
+       /*!
+        * Slot. Fetches meetings from the server. Parameters are hard coded: the meetings of the default
+        * room from current and +/- 2 weeks are fetched.
+        */
+       void fetchMeetings();
+       //! Slot. Saves fetched meetings to the current instance's local storage.
+       /*!
+        * Slot. Saves fetched meetings to the current instance's local storage. Meetings are soted in a
+        * private QList, it is iterated through and signals are emitted if there is any new, updated or
+        * deleted meeting.
+        * \param aMeetings The list of freshly fetched meetings.
+        */
+       void meetingsFetched( const QList<Meeting*>& );
+       
+       void meetingDetailsFetched( Meeting &aDetailedMeeting );
+       
+       //! Slot. Checks the availability of all the rooms.
+       /*!
+        * Slot. Checks the availability of all the rooms by iterating through the current object's local
+        * room storage and calling the roomStatusInfoNeeded() separately on each of them.
+        */
+       void checkStatusOfAllRooms();
+
+private:
+       //! Provides the index of the Meeting instance which is at the specified time.
+       /*!
+        * Provides the index of the Meeting instance which is at the specified time. If there are
+        * overlapping meetings then returns one of then undetetministically.
+        * \param aRoom The room which meetings are looked through.
+        * \param aAt Date and time when the meeting is already going.
+        * \return Index of the meeting if found; otherwise, -1.
+        */
+       int indexOfMeetingAt( Room *aRoom, QDateTime aAt );
+       //! Provides the index of the Meeting instance which is starts the closest to the specified time.
+       /*!
+        * Provides the index of the Meeting instance which is starts the closest to the specified time.
+        * If there are overlapping meetings then returns one of then undetetministically.
+        * \param aRoom The room which meetings are looked through.
+        * \param aAt Date and time when the meeting is not yet started.
+        * \return Index of the meeting if found; otherwise, -1.
+        */
+       int indexOfMeetingAfter( Room *aRoom, QDateTime aAfter );
+       //! Indicates if the QList contains the Meeting or not.
+       /*!
+        * Indicates if the QList contains the Meeting or not.
+        * \param aList List of meetings.
+        * \param aMeeting The meeting which is seeked in the list for.
+        * \return True if contains; otherwise, false.
+        */
+       static bool isMeetingInList( const QList<Meeting*> &aList, const Meeting *aMeeting );
+
+private:
+       static QTime endOfTheDay;
+
+       Clock *iClock;
+       Configuration *iConfiguration;
+       CommunicationManager *iCommunication;
+       DeviceManager *iDevice;
+
+       QTimer *iAutoRefresh;
+
+       QList<Meeting*> iMeetings;
+
+       Room *iCurrentRoom;     /*! Not owned */
+};
+
+#endif /*ENGINE_H_*/
diff --git a/src/BusinessLogic/Utils/Clock.cpp b/src/BusinessLogic/Utils/Clock.cpp
new file mode 100644 (file)
index 0000000..93b3163
--- /dev/null
@@ -0,0 +1,57 @@
+#include "Clock.h"
+#include <QProcess>
+#include <QTimer>
+
+const int TICK_TIME = 1000; // milliseconds
+
+Clock::Clock() :
+               QObject()
+{
+       iCurrentDateTime = QDateTime::currentDateTime();
+
+       iTimer = new QTimer;
+       iTimer->setInterval( TICK_TIME );
+       connect( iTimer, SIGNAL( timeout() ), iTimer, SLOT( start() ) );
+       connect( iTimer, SIGNAL( timeout() ), this, SLOT( update() ) );
+       iTimer->start();
+}
+
+Clock::~Clock()
+{
+       if ( iTimer != 0 )
+       {
+               iTimer->stop();
+               delete iTimer;
+       }
+}
+
+QDateTime Clock::datetime()
+{
+       return iCurrentDateTime;
+}
+
+QDate Clock::today()
+{
+       return iCurrentDateTime.date();
+}
+
+QTime Clock::time()
+{
+       return iCurrentDateTime.time();
+}
+
+void Clock::syncronizeDateTime()
+{
+       const QString systemCmd = "sudo /etc/init.d/openntpd restart";
+
+       iTimer->stop();
+       QProcess::execute( systemCmd );
+       iTimer->start();
+}
+
+void Clock::update()
+{
+       iCurrentDateTime = QDateTime::currentDateTime();
+
+       emit tick( datetime() );
+}
diff --git a/src/BusinessLogic/Utils/Clock.h b/src/BusinessLogic/Utils/Clock.h
new file mode 100644 (file)
index 0000000..13cffdc
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef CLOCK_H_
+#define CLOCK_H_
+
+#include <QObject>
+#include <QDateTime>
+
+class QTimer;
+
+//! BusinessLogic class. Provide up-to-date date and time for the whole application.
+/*!
+ * BusinessLogic class. Provide up-to-date date and time for the whole application. The class uses
+ * openNTPD to syncronize local datetime with a remote NTP server. The NTP client must be configured.
+ * The class uses ticks in every minute and signals the actual datetime information.
+ */
+class Clock : public QObject
+{
+       Q_OBJECT
+
+public:
+       //! Contructor.
+       /*!
+        * Contructor to initialize a new Clock instance.
+        */
+       Clock();
+       //! Destructor.
+       virtual ~Clock();
+
+       //! Gets the current date and time.
+       /*!
+        * Gets the current date and time.
+        * \return The current date and time.
+        */
+       QDateTime datetime();
+       //! Gets the current day.
+       /*!
+        * Gets the current day.
+        * \return The current day.
+        */
+       QDate today();
+       //! Gets the current time.
+       /*!
+        * Gets the current time.
+        * \return The current time.
+        */
+       QTime time();
+
+signals:
+       //! Signal. Emitted in every second, it signals the actual date and time info.
+       /*!
+        * Signal. Emitted in every second, it signals the actual date and time info.
+        * \param aCurrentDateTime The current date and time.
+        */
+       void tick( QDateTime aCurrentDateTime );
+
+public slots:
+       //! Slot. Syncronizes the devices local date and time with a remote NTP server.
+       /*!
+        * Slot. Syncronizes the devices local date and time with a remote NTP server by using
+        * openNTPD client. It launches the installed and configured klient with a system command.
+        */
+       void syncronizeDateTime();
+
+private slots:
+       //! Slot. Updates the date and time info stored in the current instance.
+       /*!
+        * Slot. Updates the date and time info stored in the current instance by reading the device's clock.
+        */
+       void update();
+
+private:
+       QDateTime iCurrentDateTime;
+       QTimer* iTimer;
+};
+
+#endif /*CLOCK_H_*/
diff --git a/src/BusinessLogic/Utils/ErrorMapper.cpp b/src/BusinessLogic/Utils/ErrorMapper.cpp
new file mode 100644 (file)
index 0000000..58dfc8c
--- /dev/null
@@ -0,0 +1,83 @@
+#include "ErrorMapper.h"\r
+\r
+#include <QDomDocument>\r
+#include <QDomElement>\r
+#include <QDomNode>\r
+#include <QFile>\r
+\r
+#include <QtDebug>\r
+\r
+ErrorMapper * ErrorMapper::sInstance = 0;\r
+QString ErrorMapper::sNotValidErrorCode = QString( "ABC" );\r
+\r
+ErrorMapper::ErrorMapper()\r
+{\r
+       Q_INIT_RESOURCE( BusinessLogic );\r
+       mapFromXML( ":/errortable" );\r
+}\r
+\r
+ErrorMapper::~ErrorMapper()\r
+{\r
+}\r
+\r
+void ErrorMapper::mapFromXML( const QString &aXml )\r
+{\r
+       // create and xml reader\r
+       QDomDocument doc;\r
+       QFile file( aXml );\r
+\r
+       // open the file\r
+       if ( !file.open( QIODevice::ReadOnly ) )\r
+       {\r
+               return;\r
+       }\r
+\r
+       // associate the content to the xml reader\r
+       if ( !doc.setContent( &file ) )\r
+       {\r
+               file.close();\r
+               return;\r
+       }\r
+       file.close();\r
+\r
+       // start readin the xml file\r
+       QDomElement root = doc.documentElement();\r
+       // check if the file is the one we need\r
+       if ( root.tagName().toLower() != "errors" )\r
+       {\r
+               return;\r
+       }\r
+\r
+       // loop through the nodes\r
+       for ( QDomNode node = root.firstChild(); !node.isNull(); node = node.nextSibling() )\r
+       {\r
+               // read an element in the xml file\r
+               QDomElement e = node.toElement();\r
+               if ( !e.isNull() && e.tagName().toLower() == "error" )\r
+               {\r
+                       bool success = false;\r
+                       int code = QString( e.attribute( "code", sNotValidErrorCode ) ).toInt( &success );\r
+                       QString text = e.text();\r
+\r
+                       // if element is correct, then store it\r
+                       if ( success )\r
+                       {\r
+                               iErrorTable.insert( code, text );\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+QString ErrorMapper::codeToString( int code, const QString &aAddInfo )\r
+{\r
+       if ( sInstance == 0 )\r
+       {\r
+               sInstance = new ErrorMapper;\r
+       }\r
+       \r
+       QString text = sInstance->iErrorTable.value( code, "" );\r
+       if( aAddInfo != "" && text.contains( "%1" ) )\r
+               text = text.arg( "%1" ).arg( aAddInfo );\r
+       \r
+       return text;\r
+}\r
diff --git a/src/BusinessLogic/Utils/ErrorMapper.h b/src/BusinessLogic/Utils/ErrorMapper.h
new file mode 100644 (file)
index 0000000..01e8e9b
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef ERRORMAPPER_H_\r
+#define ERRORMAPPER_H_\r
+\r
+#include <QString>\r
+#include <QMap>\r
+\r
+//! BusinessLogic class. Map error codes to error strings.\r
+/*!\r
+ * BusinessLogic class. Map error codes to error strings. The code-string pairs are defined in XML-file\r
+ * which is read by the mapper at initialization and stored in a QMap. The class has only one public\r
+ * static method which provides access to the code-string table, there is a static instance used but this\r
+ * is transparent for the caller.\r
+ */\r
+class ErrorMapper\r
+{\r
+\r
+public:\r
+       //! Gets the error string of the specified error code.\r
+       /*!\r
+        * Gets the error string of the specified error code.\r
+        * \param aCode The code to which the string must be got.\r
+        * \param aAddInfo Possible additional info.\r
+        * \return The string pair of the specified code, if found; otherwise, empty string.\r
+        */\r
+       static QString codeToString( int aCode, const QString &aAddInfo = "" );\r
+\r
+private:\r
+       //! Constructor.\r
+       /*!\r
+        * Constructor to initialize an ErrorMapper instance.\r
+        */\r
+       ErrorMapper();\r
+       //! Destructor.\r
+       virtual ~ErrorMapper();\r
+\r
+       //! Loads to code-string pairs.\r
+       /*!\r
+        * Loads to code-string pairs from XML-file to a QMap object.\r
+        * \param aXml The XML-file which contains the error table.\r
+        */\r
+       void mapFromXML( const QString &aXml );\r
+\r
+private:\r
+       /*!\r
+        * The static instance which is in use to load and store the code-string pairs.\r
+        */\r
+       static ErrorMapper *sInstance;\r
+       static QString sNotValidErrorCode;\r
+\r
+       QMap<int, QString> iErrorTable;\r
+\r
+};\r
+\r
+#endif /*ERRORMAPPER_H_*/\r
diff --git a/src/Domain/Configuration/Configuration.cpp b/src/Domain/Configuration/Configuration.cpp
new file mode 100644 (file)
index 0000000..9286846
--- /dev/null
@@ -0,0 +1,601 @@
+#include "Configuration.h"
+#include "ConnectionSettings.h"
+#include "StartupSettings.h"
+#include "DisplaySettings.h"
+#include "Room.h"
+#include <QDomDocument>
+#include <QDomElement>
+#include <QDomNode>
+#include <QFile>
+#include <QCryptographicHash>
+
+#include <QtDebug>
+
+Configuration * Configuration::sInstance = 0;
+QString Configuration::sConfigurationPath = "/etc/QtMeetings.conf";
+
+Configuration::Configuration() :
+               iConnectionSettings( 0 ),
+               iStartupSettings( 0 ),
+               iDisplaySettings( 0 )
+{
+}
+
+Configuration::~Configuration()
+{
+       delete iConnectionSettings;
+       delete iStartupSettings;
+       delete iDisplaySettings;
+       while ( !iRooms.isEmpty() )
+       {
+               delete iRooms.takeFirst();
+       }
+}
+
+Configuration* Configuration::instance()
+{
+       if ( sInstance == 0 )
+       {
+               sInstance = readFromXML( sConfigurationPath );
+        if( !sInstance )
+        {
+            qDebug() << "FATAL: Configuration cannot be read from:" << Configuration::sConfigurationPath;
+        }
+    }
+       return sInstance;
+}
+
+ConnectionSettings* Configuration::connectionSettings()
+{
+       return iConnectionSettings;
+}
+
+StartupSettings * Configuration::startupSettings()
+{
+       return iStartupSettings;
+}
+
+DisplaySettings * Configuration::displaySettings()
+{
+       return iDisplaySettings;
+}
+
+Room* Configuration::defaultRoom()
+{
+       // default room is stored as the first element of the list
+       return ( iRooms.count() == 0 ) ? 0 : iRooms.at( 0 );
+}
+
+QString Configuration::languageCode()
+{
+       return iLanguageCode;
+}
+
+QList<Room*> Configuration::rooms()
+{
+       return iRooms;
+}
+
+QByteArray Configuration::adminPassword()
+{
+       return iAdminPassword;
+}
+
+void Configuration::save()
+{
+       QDomDocument doc;
+       QFile file( sConfigurationPath );
+
+       if ( !file.open( QIODevice::ReadWrite ) )
+       {
+               return;
+       }
+
+       if ( !doc.setContent( &file ) )
+       {
+               file.close();
+               return;
+       }
+
+       QDomElement root = doc.documentElement();
+       // Save all attributes to document
+
+       saveAdminPassword( root );
+
+       for ( QDomNode node = root.firstChild(); !node.isNull(); node = node.nextSibling() )
+       {
+               QDomElement e = node.toElement();
+               QString tagName = e.tagName().toLower();
+
+               if ( tagName == QString( "connection" ) )
+               {
+                       saveConnectionSettings( node );
+               }
+               else if ( tagName == QString( "rooms" ) )
+               {
+                       saveRooms( node );
+               }
+               else if ( tagName == QString( "language" ) )
+               {
+                       saveLanguageCode( node );
+               }
+               else if ( tagName == QString( "startup" ) )
+               {
+                       saveStartupSettings( node );
+               }
+               else if ( tagName == QString( "display" ) )
+               {
+                       saveDisplaySettings( node );
+               }
+       }
+
+       //! Empty the file from previous content and write again with new one
+       file.resize( 0 );
+       file.write( doc.toByteArray( 4 ) );     //! 4 as intent
+
+       file.close();
+
+}
+
+void Configuration::saveConnectionSettings( const QDomNode &aXML )
+{
+       for ( QDomNode node = aXML.firstChild(); !node.isNull(); node = node.nextSibling() )
+       {
+               QDomElement e = node.toElement();
+               QString tagName = e.tagName().toLower();
+
+               if ( tagName == QString( "serverurl" ) )
+               {
+                       QDomText t = node.ownerDocument().createTextNode( iConnectionSettings->serverUrl().toString() );
+                       e.replaceChild( t, e.firstChild() );
+               }
+               else if ( tagName == QString( "username" ) )
+               {
+                       QDomText t = node.ownerDocument().createTextNode( iConnectionSettings->username() );
+                       e.replaceChild( t, e.firstChild() );
+               }
+               else if ( tagName == QString( "password" ) )
+               {
+                       QDomText t = node.ownerDocument().createTextNode( iConnectionSettings->password() );
+                       e.replaceChild( t, e.firstChild() );
+               }
+               else if ( tagName == QString( "refreshinterval" ) )
+               {
+                       QString s = QString( "%1" ).arg( iConnectionSettings->refreshInterval() );
+                       QDomText t = node.ownerDocument().createTextNode( s );
+                       e.replaceChild( t, e.firstChild() );
+               }
+       }
+}
+
+void Configuration::saveRooms( const QDomNode &aXML )
+{
+       //! List of rooms must be cleared and rewritten again
+       QDomDocument doc = aXML.ownerDocument();
+       QDomNode root = aXML; 
+
+       // Remove child nodes...
+       int count = root.childNodes().count();
+       QDomNode node = root.firstChild();
+       QDomNode next;
+       for (int i=0; i<count; i++)
+       {
+               qDebug() << "remove " << node.toElement().text();
+               next = node.nextSibling();
+               node = root.removeChild(node);
+               node = next;
+       }
+
+       QList<Room*>::iterator i;
+       for ( i = iRooms.begin(); i != iRooms.end(); ++i )
+       {
+               QDomElement tag = doc.createElement( "room" );
+               node.appendChild( tag );
+
+               // First room in the list is a dafault room
+               if ( i == iRooms.begin() )
+               {
+                       tag.setAttribute( "default", "true" );
+               }
+
+               QDomElement ename = doc.createElement( "name" );
+               QDomText tname = node.ownerDocument().createTextNode(( *i )->name() );
+               ename.appendChild( tname );
+               tag.appendChild( ename );
+
+               QDomElement eaddress = doc.createElement( "address" );
+               QDomText taddress = node.ownerDocument().createTextNode(( *i )->address() );
+               eaddress.appendChild( taddress );
+               tag.appendChild( eaddress );
+       }
+}
+
+void Configuration::saveLanguageCode( const QDomNode &aXML )
+{
+       QDomElement e = aXML.toElement();
+       e.setAttribute( "code", languageCode() );
+}
+
+void Configuration::saveStartupSettings( const QDomNode &aXML )
+{
+       QDomElement e = aXML.toElement();
+
+       for ( QDomNode node = aXML.firstChild(); !node.isNull(); node = node.nextSibling() )
+       {
+               e = node.toElement();
+               QString tagName = e.tagName().toLower();
+
+               if ( tagName == QString( "powersaving" ) )
+               {
+                       ( iStartupSettings->isPowersavingEnabled() ?
+                         e.setAttribute( "enabled", "true" ) :
+                         e.setAttribute( "enabled", "false" ) );
+
+                       e.setAttribute( "on", iStartupSettings->turnOnAt().toString( "hh:mm" ) );
+                       e.setAttribute( "off", iStartupSettings->turnOffAt().toString( "hh:mm" ) );
+               }
+       }
+}
+
+void Configuration::saveDisplaySettings( const QDomNode &aXML )
+{
+       for ( QDomNode node = aXML.firstChild(); !node.isNull(); node = node.nextSibling() )
+       {
+               QDomElement e = node.toElement();
+               QString tagName = e.tagName().toLower();
+
+               if ( tagName == QString( "schedule" ) )
+               {
+                       for ( QDomNode scheduleNode = node.firstChild(); !scheduleNode.isNull(); scheduleNode = scheduleNode.nextSibling() )
+                       {
+                               QDomElement scheduleElem = scheduleNode.toElement();
+                               tagName = scheduleElem.tagName().toLower();
+
+                               if ( tagName == QString( "week" ) )
+                               {
+                                       scheduleElem.setAttribute( "days", iDisplaySettings->daysInSchedule() );
+                               }
+                               else if ( tagName == QString( "day" ) )
+                               {
+                                       scheduleElem.setAttribute( "startsat", iDisplaySettings->dayStartsAt().toString( "hh:mm" ) );
+                                       scheduleElem.setAttribute( "endsat", iDisplaySettings->dayEndsAt().toString( "hh:mm" ) );
+                               }
+                       }       // end of for
+               }       // end of schedule
+               else if ( tagName == QString( "dateformat" ) )
+               {
+                       QDomText t = node.ownerDocument().createTextNode( iDisplaySettings->dateFormat() );
+                       e.replaceChild( t, e.firstChild() );
+               }
+               else if ( tagName == QString( "timeformat" ) )
+               {
+                       QDomText t = node.ownerDocument().createTextNode( iDisplaySettings->timeFormat() );
+                       e.replaceChild( t, e.firstChild() );
+               }
+               else if ( tagName == QString( "screensaver" ) )
+               {
+                       QString s = QString( "%1" ).arg( iDisplaySettings->screensaver() );
+                       QDomText t = node.ownerDocument().createTextNode( s );
+                       e.replaceChild( t, e.firstChild() );
+               }
+       }
+}
+
+void Configuration::saveAdminPassword( const QDomNode &aXML )
+{
+       QDomElement e = aXML.toElement();
+       e.setAttribute( "password", QString( adminPassword() ) );
+}
+
+
+Configuration* Configuration::readFromXML( const QString &aPath )
+{
+       QDomDocument doc;
+       QFile file( aPath );
+
+       if ( !file.open( QIODevice::ReadOnly ) )
+       {
+               return 0;
+       }
+       if ( !doc.setContent( &file ) )
+       {
+               file.close();
+               return 0;
+       }
+       file.close();
+
+       QDomElement root = doc.documentElement();
+       // check if the file is the one we need
+       if ( root.tagName().toLower() != QString( "configuration" ) )
+       {
+               return 0;
+       }
+
+       Configuration* conf = new Configuration();
+
+       conf->iAdminPassword = Configuration::readAdminPassword( root );
+
+       for ( QDomNode node = root.firstChild(); !node.isNull(); node = node.nextSibling() )
+       {
+               QDomElement e = node.toElement();
+               QString tagName = e.tagName().toLower();
+
+               if ( tagName == QString( "connection" ) )
+               {
+                       conf->iConnectionSettings = Configuration::readConnectionSettings( node );
+               }
+               else if ( tagName == QString( "rooms" ) )
+               {
+                       conf->iRooms = Configuration::readRooms( node );
+               }
+               else if ( tagName == QString( "language" ) )
+               {
+                       conf->iLanguageCode = Configuration::readLanguageCode( node );
+               }
+               else if ( tagName == QString( "startup" ) )
+               {
+                       conf->iStartupSettings = Configuration::readStartupSettings( node );
+               }
+               else if ( tagName == QString( "display" ) )
+               {
+                       conf->iDisplaySettings = Configuration::readDisplaySettings( node );
+               }
+       }
+
+       return conf;
+}
+
+ConnectionSettings* Configuration::readConnectionSettings( const QDomNode &aXML )
+{
+       QString server, username, password;
+       unsigned int interval = Configuration::sDefaultInterval;
+
+       for ( QDomNode node = aXML.firstChild(); !node.isNull(); node = node.nextSibling() )
+       {
+               QDomElement e = node.toElement();
+               QString tagName = e.tagName().toLower();
+
+               if ( tagName == QString( "serverurl" ) )
+               {
+                       server = e.text();
+               }
+               else if ( tagName == QString( "username" ) )
+               {
+                       username = e.text();
+               }
+               else if ( tagName == QString( "password" ) )
+               {
+                       password = e.text();
+               }
+               else if ( tagName == QString( "refreshinterval" ) )
+               {
+                       bool success = false;
+                       unsigned int intervalTMP = e.text().toUInt( &success );
+                       if ( success )
+                       {
+                               interval = intervalTMP;
+                       }
+               }
+       }
+
+       return new ConnectionSettings( server, username, password, interval );
+}
+
+QList<Room*> Configuration::readRooms( const QDomNode &aXML )
+{
+       QList<Room*> rooms;
+
+       for ( QDomNode node = aXML.firstChild(); !node.isNull(); node = node.nextSibling() )
+       {
+               QDomElement e = node.toElement();
+               QString tagName = e.tagName().toLower();
+
+               if ( tagName == QString( "room" ) )
+               {
+                       QString name, address;
+
+                       for ( QDomNode roomNode = node.firstChild(); !roomNode.isNull(); roomNode = roomNode.nextSibling() )
+                       {
+                               QDomElement roomElem = roomNode.toElement();
+                               tagName = roomElem.tagName().toLower();
+                               if ( tagName == QString( "name" ) )
+                               {
+                                       name = roomElem.text();
+                               }
+                               else if ( tagName == QString( "address" ) )
+                               {
+                                       address = roomElem.text();
+                               }
+                       }
+                       Room* room = new Room( name, address );
+                       QString defaultAttr = e.attribute( "default" ).toLower();
+                       if ( defaultAttr == QString( "true" ) )
+                       {
+                               rooms.insert( 0, room );
+                       }
+                       else
+                       {
+                               rooms.append( room );
+                       }
+               }
+       }
+
+       return rooms;
+}
+
+QString Configuration::readLanguageCode( const QDomNode &aXML )
+{
+       QDomElement e = aXML.toElement();
+       QString tagName = e.tagName().toLower();
+
+       if ( e.hasAttribute( "code" ) )
+       {
+               return e.attribute( "code" );
+       }
+       else
+       {
+               // default language is English
+               return "EN";
+       }
+}
+
+StartupSettings * Configuration::readStartupSettings( const QDomNode &aXML )
+{
+       QDomElement e = aXML.toElement();
+
+       bool isPowersavingEnabled = false;
+       QTime turnOnAt, turnOffAt;
+
+       for ( QDomNode node = aXML.firstChild(); !node.isNull(); node = node.nextSibling() )
+       {
+               e = node.toElement();
+               QString tagName = e.tagName().toLower();
+
+               if ( tagName == QString( "powersaving" ) )
+               {
+                       if ( e.hasAttribute( "enabled" ) &&
+                                 e.attribute( "enabled" ) == QString( "true" ) )
+                       {
+                               isPowersavingEnabled = true;
+                       }
+
+                       if ( e.hasAttribute( "on" ) )
+                       {
+                               QString on = e.attribute( "on" );
+                               turnOnAt = QTime::fromString( on, "hh:mm" );
+
+                       }
+
+                       if ( e.hasAttribute( "off" ) )
+                       {
+                               QString off = e.attribute( "off" );
+                               turnOffAt = QTime::fromString( off, "hh:mm" );
+                       }
+               }
+       }
+
+       return new StartupSettings( isPowersavingEnabled, turnOnAt, turnOffAt );
+}
+
+DisplaySettings * Configuration::readDisplaySettings( const QDomNode &aXML )
+{
+       DisplaySettings::DaysInSchedule daysInSchedule;
+       QTime dayStartsAt, dayEndsAt;
+       DisplaySettings::DateFormat dateformat;
+       DisplaySettings::TimeFormat timeformat;
+       int screensaver = 1;    //! Default value for screensaver wait time
+
+       for ( QDomNode node = aXML.firstChild(); !node.isNull(); node = node.nextSibling() )
+       {
+               QDomElement e = node.toElement();
+               QString tagName = e.tagName().toLower();
+
+               if ( tagName == QString( "schedule" ) )
+               {
+                       for ( QDomNode scheduleNode = node.firstChild(); !scheduleNode.isNull(); scheduleNode = scheduleNode.nextSibling() )
+                       {
+                               QDomElement scheduleElem = scheduleNode.toElement();
+                               tagName = scheduleElem.tagName().toLower();
+
+                               if ( tagName == QString( "week" ) )
+                               {
+                                       if ( scheduleElem.hasAttribute( "days" ) )
+                                       {
+                                               // default value is 5, only other supported possibility is 7
+                                               bool success = false;
+                                               unsigned int days = scheduleElem.attribute( "days" ).toUInt( &success );
+                                               daysInSchedule = ( success && days == 7 ) ? DisplaySettings::WholeWeekInSchedule : DisplaySettings::WeekdaysInSchedule;
+                                       }
+
+                               }
+                               else if ( tagName == QString( "day" ) )
+                               {
+                                       if ( scheduleElem.hasAttribute( "startsat" ) )
+                                       {
+                                               QString time = scheduleElem.attribute( "startsat" );
+                                               dayStartsAt = QTime::fromString( time, "hh:mm" );
+                                       }
+                                       if ( scheduleElem.hasAttribute( "endsat" ) )
+                                       {
+                                               QString time = scheduleElem.attribute( "endsat" );
+                                               dayEndsAt = QTime::fromString( time, "hh:mm" );
+                                       }
+
+                               }
+                       }       // end of for
+               }       // end of schedule
+               else if ( tagName == QString( "dateformat" ) )
+               {
+                       //! Not able to display long format anyway at the moment
+                       /*
+                       if ( e.text() == QObject::tr( "dddd d MMMM yyyy" ) )
+                               dateformat = DisplaySettings::LongDateFormat;
+                       else
+                               dateformat = DisplaySettings::ShortDateFormat;
+                       */
+                       dateformat = DisplaySettings::ShortDateFormat;
+               }
+               else if ( tagName == QString( "timeformat" ) )
+               {
+                       //! Not able to display "TwelveHoursTimeFormat" anyway at the moment
+                       /*
+                       if ( e.text() == QObject::tr( "hh:mm ap" ) )
+                               timeformat = DisplaySettings::TwelveHoursTimeFormat;
+                       else
+                               timeformat = DisplaySettings::TwentyFourHoursTimeFormat;
+                       */
+                       timeformat = DisplaySettings::TwentyFourHoursTimeFormat;
+               }
+               else if ( tagName == QString( "screensaver" ) )
+               {
+                       bool success = false;
+                       unsigned int screensaverTMP = e.text().toUInt( &success );
+                       if ( success )
+                       {
+                               screensaver = screensaverTMP;
+                       }
+               }
+       }
+
+       return new DisplaySettings( dateformat, timeformat, daysInSchedule, dayStartsAt, dayEndsAt, screensaver );
+}
+
+QByteArray Configuration::readAdminPassword( const QDomNode &aXML )
+{
+       QDomElement e = aXML.toElement();
+       QString tagName = e.tagName().toLower();
+       if ( e.hasAttribute( "password" ) )
+       {
+               QString pw = e.attribute( "password" );
+               // Check if the password is default uncrypted "admin"
+               if ( pw == QString( "admin" ) )
+               {
+                       // uncrypted password needs to be encoded
+                       QCryptographicHash *hash = new QCryptographicHash( QCryptographicHash::Md5 );
+                       hash->addData( pw.toUtf8() );
+                       pw = QString( hash->result() );
+                       delete hash;
+               }
+               return ( pw.toAscii() ).toHex();
+               
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+void Configuration::setRooms( const QList<Room*> aRooms )
+{
+       iRooms = aRooms;
+}
+
+QString Configuration::hashPassword( const QString aPassword )
+{
+       QCryptographicHash *hash = new QCryptographicHash( QCryptographicHash::Md5 );
+       hash->addData( aPassword.toUtf8() );
+       QByteArray password = hash->result();
+       delete hash;
+
+       return QString( password );
+}
diff --git a/src/Domain/Configuration/Configuration.h b/src/Domain/Configuration/Configuration.h
new file mode 100644 (file)
index 0000000..c08002d
--- /dev/null
@@ -0,0 +1,217 @@
+#ifndef CONFIGURATION_H_
+#define CONFIGURATION_H_
+
+#include <QObject>
+#include <QString>
+#include <QList>
+#include <QTime>
+
+class ConnectionSettings;
+class StartupSettings;
+class DisplaySettings;
+class Room;
+class QDomNode;
+
+//! Domain class. Store application wide configuration values.
+/*!
+ * Domain class. Store application wide configuration values. The values are read from a configuration
+ * file at initialization time. Since there is one appliation per device normally running, therefore
+ * there is only one instance of this class, which is accessible by using a statis getter method.
+ */
+class Configuration : public QObject
+{
+       Q_OBJECT
+
+private:
+       //! Constructor.
+       /*!
+        * Constructor to initialize an Configuration instance. The method populates the object by reading
+        * through the application's configuration file.
+        */
+       Configuration();
+
+public:
+       //! Destructor
+       virtual ~Configuration();
+
+       //! Static. Gets the application wide configuration instance.
+       /*!
+        * Static Gets the static instance of this class. It is used to read the configuration information.
+        * \return Pointer to the Configuration instalce.
+        */
+       static Configuration* instance();
+       //! Gets the connection settings.
+       /*!
+        * Gets the connection settings.
+        * \return Pointer to ConnectionSettings instance.
+        */
+       ConnectionSettings* connectionSettings();
+       //! Gets the detault room.
+       /*!
+        * Gets the default meeting room.
+        * \return Pointer to the default room.
+        */
+       Room* defaultRoom();
+       //! Gets the language code.
+       /*!
+        * Gets the language code.
+        * \return Language code in ISO 3166-1 alpha-2 format.
+        */
+       QString languageCode();
+       //! Gets the list of meeting rooms.
+       /*!
+        * Gets the list of meeting rooms.
+        * \return List of rooms.
+        */
+       QList<Room*> rooms();
+       //! Gets startup settings.
+       /*!
+        * Gets the startup settings.
+        * \return Pointer to StartupSettings instance.
+        */
+       StartupSettings* startupSettings();
+       //! Gets display settings.
+       /*!
+        * Gets the display settings.
+        * \return Pointer to DisplaySettings instance.
+        */
+       DisplaySettings* displaySettings();
+       //! Gets the administrator's password.
+       /*!
+        * Gets the administrator's password
+        * \return Administration password.
+        */
+       QByteArray adminPassword();
+       //! Sets room list.
+       /*!
+        * Sets  room list.
+        * \param aRooms List of rooms
+        */
+       void setRooms( const QList<Room*> aRooms );
+       
+public slots:
+
+       //! Saves setting values to file.
+       /*!
+        * Writes setting values to configuration file.
+        */
+       void save();
+
+private:
+       //! Static. Reads the configuration instance from XML file.
+       /*!
+        * Static. Reads the configuration information from configuration file.
+        * \param aPath path and name of configuration file
+        * \return Configuration object.
+        */
+       static Configuration* readFromXML( const QString &aPath );
+       //! Static. Reads settings of connection from and XML node.
+       /*!
+        * Static. Reads settings of connection from an XML node.
+        * \param aXml QDomNode containing connection parameters.
+        * \return Pointer to ConnectionSettings object.
+        */
+       static ConnectionSettings* readConnectionSettings( const QDomNode &aXML );
+       //! Static. Reads rooms from an XML node.
+       /*!
+        * Static. Reads rooms from an XML node.
+        * \param aXml QDomNode containing meeting room parameters
+        * \return List of meetingrooms.
+        */
+       static QList<Room*> readRooms( const QDomNode &aXML );
+       //! Static. Reads language code from an XML node.
+       /*!
+        * Static. Reads rooms from an XML node.
+        * \param aXml QDomNode containing language code
+        * \return Language code.
+        */
+       static QString readLanguageCode( const QDomNode &aXML );
+       //! Static. Reads settings of startup from an XML node.
+       /*!
+        * Static. Reads settings of startup from an XML node.
+        * \param aXml QDomNode containing startup parameters
+        * \return Pointer to the read StartupSettings object.
+        */
+       static StartupSettings* readStartupSettings( const QDomNode &aXML );
+       /*!
+        * Static function to load and store display settings from xml node.
+        * \param aXml QDomNode containing display parameters
+        * \return Pointer to the read DisplaySettings object.
+        */
+       static DisplaySettings* readDisplaySettings( const QDomNode &aXML );
+       //! Static. Reads adminstrator's password from an XML node.
+       /*!
+        * Static. Reads adminstrator's password from an XML node.
+        * \param aXml QDomNode containing admin password
+        * \return Admin password.
+        */
+       static QByteArray readAdminPassword( const QDomNode &aXML );
+
+       //! Saves connection data to the document.
+       /*!
+        * Reads data from iConnectionSettings and saves it to the aXML document.
+        * \param aXml QDomNode containing connection parameters.
+        */
+       void saveConnectionSettings( const QDomNode &aXML );
+       //! Saves meeting rooms to the document.
+       /*!
+        * Reads data from iRooms list and saves it to the aXML document.
+        * \param aXml QDomNode containing meeting room parameters
+        */
+       void saveRooms( const QDomNode &aXML );
+       //! Saves the language code.
+       /*!
+        * Reads data from iLanguageCode and saves it to the aXML document.
+        * \param aXml QDomNode containing language code
+        */
+       void saveLanguageCode( const QDomNode &aXML );
+       //! Saves startup setting data to the document.
+       /*!
+        * Reads data from iStartupSettings and saves it to the aXML document.
+        * \param aXml QDomNode containing startup parameters
+        */
+       void saveStartupSettings( const QDomNode &aXML );
+       //! Saves display setting data to the document.
+       /*!
+        * Reads data from iDisplaySettings and saves it to the aXML document.
+        * \param aXml QDomNode containing display parameters
+        */
+       void saveDisplaySettings( const QDomNode &aXML );
+       //! Saves admin password to the document.
+       /*!
+        * Reads data from iAdminPassword and saves it to the aXML document.
+        * \param aXml QDomNode containing admin password
+        */
+       void saveAdminPassword( const QDomNode &aXML );
+
+       //! Hash password with md5 method.
+       /*!
+        * Hash password with md5 method.
+        * \param aPassword password to be encoded
+        * \return Encoded password.
+        */
+       QString hashPassword( const QString aPassword );
+
+private:
+       //! Path and name of configuration file
+       static QString sConfigurationPath;
+       //! The static instance which is in use to read the configuration.
+       static Configuration *sInstance;
+       //! Static constant to store the default interval used for connection refresh.
+       static const unsigned int sDefaultInterval = 60;
+       //! Pointer to the ConnectionSettings object
+       ConnectionSettings *iConnectionSettings;
+       //! Stores startup settings.
+       StartupSettings *iStartupSettings;
+       //! Stores display settings.
+       DisplaySettings *iDisplaySettings;
+       //! List of meeting rooms.
+       QList<Room*> iRooms;
+       //! Stores administrator password.
+       QByteArray iAdminPassword;
+       //! Stores language code
+       QString iLanguageCode;
+
+};
+
+#endif /*CONFIGURATION_H_*/
diff --git a/src/Domain/Configuration/ConnectionSettings.cpp b/src/Domain/Configuration/ConnectionSettings.cpp
new file mode 100644 (file)
index 0000000..9c70168
--- /dev/null
@@ -0,0 +1,61 @@
+#include "ConnectionSettings.h"
+
+ConnectionSettings::ConnectionSettings( const QUrl &aServerUrl, const QString &aUsername, const QString &aPassword, unsigned int aRefreshInterval )
+{
+       iServerUrl = aServerUrl;
+       iUsername = aUsername;
+       iPassword = aPassword;
+       iRefreshInterval = aRefreshInterval;
+}
+
+ConnectionSettings::ConnectionSettings( const ConnectionSettings &aOther )
+{
+       this->iServerUrl = aOther.iServerUrl;
+       this->iUsername = aOther.iUsername;
+       this->iPassword = aOther.iPassword;
+       this->iRefreshInterval = aOther.iRefreshInterval;
+}
+
+ConnectionSettings::~ConnectionSettings()
+{
+}
+
+QUrl ConnectionSettings::serverUrl()
+{
+       return iServerUrl;
+}
+
+QString ConnectionSettings::username()
+{
+       return iUsername;
+}
+
+QString ConnectionSettings::password()
+{
+       return iPassword;
+}
+
+unsigned int ConnectionSettings::refreshInterval()
+{
+       return iRefreshInterval;
+}
+
+void ConnectionSettings::setServerUrl( const QUrl &aServerUrl )
+{
+       iServerUrl = aServerUrl;
+}
+
+void ConnectionSettings::setUsername( const QString &aUsername )
+{
+       iUsername = aUsername;
+}
+
+void ConnectionSettings::setPassword( const QString &aPassword )
+{
+       iPassword = aPassword;
+}
+
+void ConnectionSettings::setRefreshInterval( unsigned int aRefreshInterval )
+{
+       iRefreshInterval = aRefreshInterval;
+}
diff --git a/src/Domain/Configuration/ConnectionSettings.h b/src/Domain/Configuration/ConnectionSettings.h
new file mode 100644 (file)
index 0000000..27b399b
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef CONNECTION_H_\r
+#define CONNECTION_H_\r
+\r
+#include <QString>\r
+#include <QUrl>\r
+\r
+//! Domain class. Stores connection information.\r
+/*!\r
+ * Domain class. Stores connection information like server url, username, password and refresh\r
+ * interval.\r
+ */\r
+class ConnectionSettings\r
+{\r
+public:\r
+       //! Constructor.\r
+       /*!\r
+        * Overloaded. Constructor to initialize a ConnectionSettings instance.\r
+        * \param aServerUrl The URL of the Exchange server.\r
+        * \param aUsername The username used to log in to the server.\r
+        * \param aPassword The password used to log in to the server.\r
+        * \param aRefreshInterval The interval defines how often the server's data must be fetched. (Interpreted in seconds.)\r
+        */\r
+       ConnectionSettings( const QUrl &aServerUrl, const QString &aUsername, const QString &aPassword, unsigned int aRefreshInterval );\r
+       //! Copy constructor.\r
+       /*!\r
+        * Overloaded. Constructor to initialize a ConnectionSettings instance.\r
+        * \param aOther ConnectionSettings class to be copied.\r
+        */\r
+       ConnectionSettings( const ConnectionSettings &aOther );\r
+       //! Destructor\r
+       virtual ~ConnectionSettings();\r
+\r
+       //! Gets the server address\r
+       /*!\r
+        * Gets the server url address.\r
+        * \return Url address of server.\r
+        */\r
+       QUrl serverUrl();\r
+       //! Gets the username.\r
+       /*!\r
+        * Gets username used to connect.\r
+        * \return Username.\r
+        */\r
+       QString username();\r
+       //! Gets the password.\r
+       /*!\r
+        * Gets the password used to connect.\r
+        * \return Password.\r
+        */\r
+       QString password();\r
+       //! Gets the refresh interval.\r
+       /*!\r
+        * Gets refresh interval in seconds to read the data from server.\r
+        * \return Refresh interval.\r
+        */\r
+       unsigned int refreshInterval();\r
+\r
+       //! Sets the server address\r
+       /*!\r
+        * Sets the server url address.\r
+        * \param aServerUrl Url address of server.\r
+        */\r
+       void setServerUrl( const QUrl &aServerUrl );\r
+       //! Sets the username.\r
+       /*!\r
+        * Sets username used to connect.\r
+        * \param aUsername Username.\r
+        */\r
+       void setUsername( const QString &aUsername );\r
+       //! Sets the password.\r
+       /*!\r
+        * Sets the password used to connect.\r
+        * \param aPassword Password.\r
+        */\r
+       void setPassword( const QString &aPassword );\r
+       //! Sets the refresh interval.\r
+       /*!\r
+        * Sets refresh interval in seconds to read the data from server.\r
+        * \param aRefreshInterval Refresh interval.\r
+        */\r
+       void setRefreshInterval( unsigned int aRefreshInterval );\r
+\r
+\r
+private:\r
+       QUrl iServerUrl;\r
+       QString iUsername;\r
+       QString iPassword;\r
+       unsigned int iRefreshInterval; // in seconds\r
+\r
+};\r
+\r
+#endif /*CONNECTION_H_*/\r
diff --git a/src/Domain/Configuration/DisplaySettings.cpp b/src/Domain/Configuration/DisplaySettings.cpp
new file mode 100644 (file)
index 0000000..debe583
--- /dev/null
@@ -0,0 +1,107 @@
+#include "DisplaySettings.h"
+#include <QObject>
+
+DisplaySettings::DisplaySettings( DateFormat aDateFormat, TimeFormat aTimeFormat, DaysInSchedule aDaysInSchedule, QTime aDayStartsAt, QTime aDayEndsAt, int aScreensaver ) :
+               iDateFormat( aDateFormat ),
+               iTimeFormat( aTimeFormat ),
+               iDaysInSchedule( aDaysInSchedule ),
+               iDayStartsAt( aDayStartsAt ),
+               iDayEndsAt( aDayEndsAt ),
+               iScreensaver( aScreensaver )
+{
+}
+
+DisplaySettings::~DisplaySettings()
+{
+}
+
+QString DisplaySettings::dateFormat()
+{
+
+       QString format;
+       switch ( iDateFormat )
+       {
+               case DisplaySettings::LongDateFormat :
+               {
+                       format = QObject::tr( "dddd d MMMM yyyy" );
+                       break;
+               }
+               case DisplaySettings::ShortDateFormat :
+               default:
+               {
+                       format = QObject::tr( "ddd d MMM" );
+                       break;
+               }
+       }
+       return format;
+}
+
+QString DisplaySettings::timeFormat()
+{
+       QString format;
+       switch ( iTimeFormat )
+       {
+               case DisplaySettings::TwelveHoursTimeFormat :
+               {
+                       format = QObject::tr( "hh:mm ap" );
+                       break;
+               }
+               case DisplaySettings::TwentyFourHoursTimeFormat :
+               default:
+               {
+                       format = QObject::tr( "hh:mm" );
+                       break;
+               }
+       }
+       return format;
+}
+
+DisplaySettings::DaysInSchedule DisplaySettings::daysInSchedule()
+{
+       return iDaysInSchedule;
+}
+
+QTime DisplaySettings::dayStartsAt()
+{
+       return iDayStartsAt;
+}
+
+QTime DisplaySettings::dayEndsAt()
+{
+       return iDayEndsAt;
+}
+
+int DisplaySettings::screensaver()
+{
+       return iScreensaver;
+}
+
+void DisplaySettings::setDateFormat( DateFormat aDateFormat )
+{
+       iDateFormat = aDateFormat;
+}
+
+void DisplaySettings::setTimeFormat( TimeFormat aTimeFormat )
+{
+       iTimeFormat = aTimeFormat;
+}
+
+void DisplaySettings::setDaysInSchedule( DaysInSchedule aDaysInSchedule )
+{
+       iDaysInSchedule = aDaysInSchedule;
+}
+
+void DisplaySettings::setDayStartsAt( QTime aDayStartsAt )
+{
+       iDayStartsAt = aDayStartsAt;
+}
+
+void DisplaySettings::setDayEndsAt( QTime aDayEndsAt )
+{
+       iDayEndsAt = aDayEndsAt;
+}
+
+void DisplaySettings::setScreensaver( int aWaitTime )
+{
+       iScreensaver = aWaitTime;
+}
diff --git a/src/Domain/Configuration/DisplaySettings.h b/src/Domain/Configuration/DisplaySettings.h
new file mode 100644 (file)
index 0000000..8230297
--- /dev/null
@@ -0,0 +1,145 @@
+#ifndef DISPLAYSETTINGS_H_
+#define DISPLAYSETTINGS_H_
+
+#include <QDateTime>
+
+//! Domain class. Stores display settings.
+/*!
+ * Domain class. Stores display settings such as date and time format, number of days shown
+ * in week calendar.
+ */
+class DisplaySettings
+{
+public:
+       //! Enumeration of days shown in week calendar.
+       /*!
+        * Enumeration of days shown in week calendar.
+        */
+       enum DaysInSchedule
+       {
+               WeekdaysInSchedule = 5,  /*!< Display days from Monday till Friday. */
+               WholeWeekInSchedule = 7 /*!< Display days from Monday till Sunday. */
+       };
+
+       //! Enumeration of used date format.
+       /*!
+        * Enumeration of used date format.
+        */
+       enum DateFormat
+       {
+               LongDateFormat, /*!< Date displayed like "Monday 6 April 2009". */
+               ShortDateFormat /*!< Date displayed like "Mon 6 Apr". */
+       };
+
+       //! Enumeration of used time format.
+       /*!
+        * Enumeration of used time format.
+        */
+       enum TimeFormat
+       {
+               TwelveHoursTimeFormat, /*!< Time displayed like "01:34 pm". */
+               TwentyFourHoursTimeFormat /*!< Time displayed like "13:34". */
+       };
+
+public:
+       //! Constructor
+       /*!
+        * Constuctor to initialize DisplaySettings instance.
+        * \param aDateFormat DateFormat type variable to eliminate the date format in use.
+        * \param aTimeFormat TimeFormat type variable to eliminate the time in use.
+        * \param aDaysInSchedule Indicates how many days are shown in the schedule.
+        * \param aDayStartsAt Time which the schedule starts with.
+        * \param aDayEndsAt Time which the schedule ends with.
+        * \param aScreensaver Minutes for timer to launch screensaver.
+        */
+       DisplaySettings( DateFormat aDateFormat, TimeFormat aTimeFormat, DaysInSchedule aDaysInSchedule, QTime aDayStartsAt, QTime aDayEndsAt, int aScreensaver );
+       //! Destructor.
+       virtual ~DisplaySettings();
+
+
+       //! Gets date format.
+       /*!
+        * Gets date format.
+        * \return Format string to display date.
+        */
+       QString dateFormat();
+       //! Gets time format.
+       /*!
+        * Gets time format.
+        * \return Format string to display time.
+        */
+       QString timeFormat();
+       //! Gets number of days in week calendar.
+       /*!
+        * Gets number of days in week calendar.
+        * \return Number of days to be shown.
+        */
+       DaysInSchedule daysInSchedule();
+       //! Gets first hour to be shown in calendar.
+       /*!
+        * Gets first hour to be shown in calendar.
+        * \return First visible hour in calendar.
+        */
+       QTime dayStartsAt();
+       //! Gets last hour to be shown in calendar.
+       /*!
+        * Gets last hour to be shown in calendar.
+        * \return Last visible hour in calendar.
+        */
+       QTime dayEndsAt();
+
+       //! Gets minutes to wait before screensaver launches.
+       /*!
+        * Gets minutes to wait before screensaver launches.
+        * \return Waiting time in minutes.
+        */
+       int screensaver();
+
+       //! Sets date format.
+       /*!
+        * Sets date format.
+        * \param aDateFormat Enumeration of date format.
+        */
+       void setDateFormat( DateFormat aDateFormat );
+       //! Sets time format.
+       /*!
+        * Sets time format.
+        * \param aTimeFormat Enumeration of time format.
+        */
+       void setTimeFormat( TimeFormat aTimeFormat );
+       //! Sets number of days in week calendar.
+       /*!
+        * Sets number of days in week calendar.
+        * \param aDaysInSchedule Number of days to be shown.
+        */
+       void setDaysInSchedule( DaysInSchedule aDaysInSchedule );
+       //! Sets first hour to be shown in calendar.
+       /*!
+        * Sets first hour to be shown in calendar.
+        * \param aDayStartsAt First visible hour in calendar.
+        */
+       void setDayStartsAt( QTime aDayStartsAt );
+       //! Sets last hour to be shown in calendar.
+       /*!
+        * Sets last hour to be shown in calendar.
+        * \param aDayEndsAt Last visible hour in calendar.
+        */
+       void setDayEndsAt( QTime aDayEndsAt );
+       //! Sets minutes to wait before screensaver launches.
+       /*!
+        * Sets minutes to wait before screensaver launches.
+        * \param aWaitTime Waiting time as minutes.
+        */
+       void setScreensaver( int aWaitTime = 1 );
+
+private:
+       DateFormat iDateFormat;
+       TimeFormat iTimeFormat;
+       DaysInSchedule iDaysInSchedule;
+       QTime iDayStartsAt;
+       QTime iDayEndsAt;
+       int iScreensaver;
+
+};
+
+#endif /*DISPLAYSETTINGS_H_*/
diff --git a/src/Domain/Configuration/StartupSettings.cpp b/src/Domain/Configuration/StartupSettings.cpp
new file mode 100644 (file)
index 0000000..6ea4588
--- /dev/null
@@ -0,0 +1,40 @@
+#include "StartupSettings.h"
+
+StartupSettings::StartupSettings( bool aIsPowersavingEnabled, QTime aTurnOnAt, QTime aTurnOffAt ) :
+               iIsPowersavingEnabled( aIsPowersavingEnabled ),
+               iTurnOnAt( aTurnOnAt ),
+               iTurnOffAt( aTurnOffAt )
+{
+}
+
+StartupSettings::~StartupSettings()
+{
+}
+
+bool StartupSettings::isPowersavingEnabled()
+{
+       return iIsPowersavingEnabled;
+}
+
+QTime StartupSettings::turnOnAt()
+{
+       return iTurnOnAt;
+}
+
+QTime StartupSettings::turnOffAt()
+{
+       return iTurnOffAt;
+}
+
+void StartupSettings::setPowersavingEnabled( bool aEnabled )
+{
+       iIsPowersavingEnabled = aEnabled;
+}
+void StartupSettings::setTurnOnAt( QTime aTurnOn )
+{
+       iTurnOnAt = aTurnOn;
+}
+void StartupSettings::setTurnOffAt( QTime aTurnOff )
+{
+       iTurnOffAt = aTurnOff;
+}
diff --git a/src/Domain/Configuration/StartupSettings.h b/src/Domain/Configuration/StartupSettings.h
new file mode 100644 (file)
index 0000000..3aa626b
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef STARTUPSETTINGS_H_
+#define STARTUPSETTINGS_H_
+
+#include <QDateTime>
+
+//! Domain class. Stores starup settings.
+/*!
+ * Domain class. Stores starup settings.
+ */
+class StartupSettings
+{
+public:
+       //! Constructor.
+       /*!
+        * Constructor to initiazile StartupSettings instance.
+        * \param aIsPowersavingEnabled Flag which is true is powersaving enabled; otherwise, false.
+        * \param aTurnOnAt Time when the device must be turned on if flag is true.
+        * \param aTurnOffAt Time when the device must be turned off if flag is true.
+        */
+       StartupSettings( bool aIsPowersavingEnabled, QTime aTurnOnAt, QTime aTurnOffAt );
+       //! Destructor
+       virtual ~StartupSettings();
+
+       //! Gets powersaving flag.
+       /*!
+        * Gets powersaving flag.
+        * \return True if power saving option is used, otherwise false.
+        */
+       bool isPowersavingEnabled();
+       //! Gets time to turn on device.
+       /*!
+        * Gets time to turn on device.
+        * \return Time to automatically turn on device.
+        */
+       QTime turnOnAt();
+       //! Gets time to turn off device.
+       /*!
+        * Gets time to turn off device.
+        * \return Time to automatically turn off device.
+        */
+       QTime turnOffAt();
+
+       //! Sets powersaving flag.
+       /*!
+        * Sets powersaving flag.
+        * \param aEnabled If true, power saving option is used.
+        */
+       void setPowersavingEnabled( bool aEnabled );
+       //! Sets time to turn on device.
+       /*!
+        * Sets time to turn on device.
+        * \param aTurnOn Time to automatically turn on device.
+        */
+       void setTurnOnAt( QTime aTurnOn );
+       //! Sets time to turn off device.
+       /*!
+        * Sets time to turn off device.
+        * \param aTurnOff Time to automatically turn off device.
+        */
+       void setTurnOffAt( QTime aTurnOff );
+
+
+private:
+       bool iIsPowersavingEnabled;
+       QTime iTurnOnAt;
+       QTime iTurnOffAt;
+
+};
+
+#endif /*STARTUPSETTINGS_H_*/
diff --git a/src/Domain/Meeting.cpp b/src/Domain/Meeting.cpp
new file mode 100644 (file)
index 0000000..8880043
--- /dev/null
@@ -0,0 +1,150 @@
+#include "Meeting.h"
+#include "Room.h"
+
+Meeting::Meeting( const QString &aPrimaryId,
+                                 const Room &aRoom,
+                                 const QDateTime &aStartsAt,
+                                 const QDateTime &aEndsAt,
+                                 const QString &aSubject,
+                                 const QString &aOrganizerName,
+                                 const QString &aOrganizerEMail,
+                                 const QString &aDescription ) :
+               iPrimaryId( aPrimaryId ),
+               iSecondaryId( QString::null ),
+               iRoom( aRoom ),
+               iStartsAt( aStartsAt ),
+               iEndsAt( aEndsAt ),
+               iSubject( aSubject ),
+               iOrganizerName( aOrganizerName ),
+               iOrganizerEMail( aOrganizerEMail ),
+               iDescription( aDescription ),
+               iDetailsAvailable( false )
+{
+}
+
+Meeting::~Meeting()
+{
+}
+
+Room Meeting::room() const
+{
+       return iRoom;
+}
+
+QString Meeting::primaryId() const
+{
+       return iPrimaryId;
+}
+
+QString Meeting::secondaryId() const
+{
+       return iSecondaryId;
+}
+
+QString Meeting::organizer() const
+{
+       if ( iOrganizerName == "" && iOrganizerEMail != "" )
+       {
+               return iOrganizerEMail;
+       }
+       if ( iOrganizerName != "" && iOrganizerEMail == "" )
+       {
+               return iOrganizerName;
+       }
+       if ( iOrganizerEMail == "" && iOrganizerName == "" )
+       {
+               return "";
+       }
+       return QString( "%1 <%2>" ).arg( iOrganizerName ).arg( iOrganizerEMail );
+
+}
+
+QDateTime Meeting::startsAt() const
+{
+       return iStartsAt;
+}
+
+QDateTime Meeting::endsAt() const
+{
+       return iEndsAt;
+}
+
+QString Meeting::subject() const
+{
+       return iSubject;
+}
+
+QString Meeting::description() const
+{
+       return iDescription;
+}
+
+bool Meeting::detailsAvailable() const
+{
+       return iDetailsAvailable;
+}
+
+void Meeting::setSecondaryId( const QString& aSecondaryId )
+{
+       iSecondaryId = aSecondaryId;
+       iDetailsAvailable = true;
+}
+
+void Meeting::setOrganizer( const QString &aOrganizerName, const QString &aOrganizerEMail )
+{
+       iOrganizerName = aOrganizerName;
+       iOrganizerEMail = aOrganizerEMail;
+}
+
+void Meeting::setStartsAt( QDateTime aNewStart )
+{
+       iStartsAt = aNewStart;
+}
+
+void Meeting::setEndsAt( QDateTime aNewEnd )
+{
+       iEndsAt = aNewEnd;
+}
+
+void Meeting::setSubject( const QString &aSubject )
+{
+       iSubject = aSubject;
+}
+
+void Meeting::setDescription( const QString &aDescription )
+{
+       iDescription = aDescription;
+}
+
+bool Meeting::equals( const Meeting &aOther ) const
+{
+       if ( iRoom.equals( aOther.room() )
+                 && iStartsAt == aOther.iStartsAt
+                 && iEndsAt == aOther.iEndsAt
+                 && iPrimaryId == aOther.iPrimaryId )
+       {
+               return true;
+       }
+       return false;
+}
+
+bool Meeting::overlaps( const Meeting &aOther ) const
+{
+       return (( iStartsAt >= aOther.iStartsAt && iStartsAt < aOther.iEndsAt ) ||
+                 ( iStartsAt <= aOther.iStartsAt && iEndsAt > aOther.iStartsAt ) );
+}
+
+QString Meeting::toString() const
+{
+       QString meetingToString = QString( "[MEETING: id1:%1 id2:%2 in:%3 from:%4 until:%5 by:%6 subject:%7 description:%8]" )
+                                         .arg( iPrimaryId )
+                                         .arg( iSecondaryId )
+                                         .arg( iRoom.toString() )
+                                         .arg( iStartsAt.toString() )
+                                         .arg( iEndsAt.toString() )
+                                         .arg( organizer() )
+                                         .arg( iSubject )
+                                         .arg( iDescription );
+
+       return meetingToString;
+}
diff --git a/src/Domain/Meeting.h b/src/Domain/Meeting.h
new file mode 100644 (file)
index 0000000..78850eb
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef MEETING_H_
+#define MEETING_H_
+
+#include <QString>
+#include <QDateTime>
+#include "Room.h"
+
+//! Domain class. Describe appointments on Microsoft Exchange Server 2007.
+/*!
+ * Domain class. Describe appointments on Microsoft Exchange Server 2007.
+ */
+class Meeting
+{
+public:
+       //! Constructor.
+       /*!
+        * Constructor to initialize a Meeting instance.
+        * \param aRoom Pointer to the Room instance where the meeting will be held.
+        * \param aStartsAt The date and time when the meeting starts.
+        * \param aEndsAt The date and time when the meeting ends.
+        * \param aOrganizer The e-mail address of the organizer.
+        * \param aSubject The subject of the meeting.
+        */
+       Meeting( const QString &aPrimaryId,
+                        const Room &aRoom,
+                        const QDateTime &aStartsAt,
+                        const QDateTime &aEndsAt,
+                        const QString &aSubject = "",
+                        const QString &aOrganizerName = "",
+                        const QString &aOrganizerEMail = "",
+                        const QString &aDescription = "" );
+       //! Destructor.
+       virtual ~Meeting();
+       //! Gets the primary identifier of the meeting.
+       /*!
+        * Gets the primary identifier of the meeting. The primary ID comes from the availability service
+        * which is used in Communication module to fetch the meetings at first. Secondary ID is needed to
+        * get more details of the meeting when user wants to open MeetingInfoDialog by clicking on cerain
+        * meeting in the schedule.
+        * \return Primary ID might be provided by the Microsoft Exchange Availability Service.
+        */
+       QString primaryId() const;
+       //! Gets the secondary identifier of the meeting.
+       /*!
+        * Gets the secondary identifier of the meeting. The primary ID comes from the availability service
+        * which is used in Communication module to fetch the meetings at first. Secondary ID is needed to
+        * get more details of the meeting when user wants to open MeetingInfoDialog by clicking on cerain
+        * meeting in the schedule.
+        * \return Secondary ID is provided by the translating the Primary one to Secondaty.
+        */
+       QString secondaryId() const;
+       //! Gets the room where the meeting is held.
+       /*!
+        * Gets the Room instance which identified the location of the meeting.
+        * \return Pointer to the Room instance.
+        */
+       Room room() const;
+       //! Gets the organizer.
+       /*!
+        * Gets formatted string which contains the organizer's name and mail address.
+        * \return The organizer's name and mail address.
+        */
+       QString organizer() const;
+       //! Gets the date and time when the meeting starts.
+       /*!
+        * Gets the date and time when the meeting starts.
+        * \return The date and time.
+        */
+       QDateTime startsAt() const;
+       //! Gets the date and time when the meeting ends.
+       /*!
+        * Gets the date and time when the meeting ends.
+        * \return The date and time.
+        */
+       QDateTime endsAt() const;
+       //! Gets the subject of the meeting.
+       /*!
+        * Gets the subject of the meeting.
+        * \return The description of the meeting's subject.
+        */
+       QString subject() const;
+       //! Gets the description of the meeting.
+       /*!
+        * Gets the description of the meeting. This field is a detailed description of the topic of the
+        * meeting provided by the meeting organizer. Note it can contain confidential information.
+        * \return The description of the meeting.
+        */
+       QString description() const;
+       //! Indicates if all the details of the current Meeting instance are available or not.
+       /*!
+        * Indicates if all the details of the current Meeting instance are available or not. If yes, then
+        * Secondary ID is valid, otherwise not.
+        * \return TRUE if yes; otherwise, false.
+        */
+       bool detailsAvailable() const;
+
+       //! Sets the secondary Id of the current meeting.
+       /*!
+        * Sets the secondary Id of the current meeting.
+        * \param aSecondaryId The secondary ID provided by translating to Primary into Secondary.
+        */
+       void setSecondaryId( const QString& aSecondaryId );
+       //! Sets the organizer of the meeting.
+       /*!
+        * Sets the organizer of the meeting.
+        * \param aOrganizerName The name of the organizer.
+        * \param aOrganizerEMail The e-mail address of the organizer.
+        */
+       void setOrganizer( const QString &aOrganizerName, const QString &aOrganizerEMail );
+       //! Sets the date and time when the meeting starts.
+       /*!
+        * Sets the date and time when the meeting starts.
+        * \param aNewStart The new date and time.
+        */
+       void setStartsAt( QDateTime aNewStart );
+       //! Sets the date and time when the meeting endss.
+       /*!
+        * Sets the date and time when the meeting endss.
+        * \param aNewEnd The new date and time.
+        */
+       void setEndsAt( QDateTime aNewEnd );
+       //! Sets new subject to the meeting.
+       /*!
+        * Sets new subject to the meeting.
+        * \param aSubject The description of the new subject.
+        */
+       void setSubject( const QString &aSubject );
+       //! Sets new description to the meeting.
+       /*!
+        * Sets new description to the meeting.
+        * \param aDescription The description of the meeting.
+        */
+       void setDescription( const QString &aDescription );
+       //! Checks if two objects are equal.
+       /*!
+        * Checks if the another same type object is equal to the current instance.
+        * \param *aOther The pointer to another Meeting class instance.
+        * \return TRUE if equals; otherwise, FALSE.
+        */
+       bool equals( const Meeting &aOther ) const;
+       //! Checks if two Meetings are overlaping.
+       /*!
+        * Checks if the current Meeting instance overlaps the parameter one.
+        * \param *aOther The pointer to another Meeting class instance.
+        * \return TRUE if overlaps; otherwise, FALSE.
+        */
+       bool overlaps( const Meeting &aOther ) const;
+       //! Makes a string to identify a meeting.
+       /*!
+        * Makes string representation of the current Meeting instance.
+        * \return The string.
+        */
+       QString toString() const;
+
+private:
+       QString iPrimaryId;
+       QString iSecondaryId;
+       Room iRoom;
+       QDateTime iStartsAt;
+       QDateTime iEndsAt;
+       QString iSubject;
+       QString iOrganizerName;
+       QString iOrganizerEMail;
+       QString iDescription;
+       bool iDetailsAvailable;
+
+};
+
+#endif /*MEETING_H_*/
diff --git a/src/Domain/Room.cpp b/src/Domain/Room.cpp
new file mode 100644 (file)
index 0000000..749152e
--- /dev/null
@@ -0,0 +1,45 @@
+#include "Room.h"
+
+Room::Room( const QString &aName, const QString &aAddress )
+{
+       this->iName = aName;
+       this->iAddress = aAddress;
+}
+
+Room::~Room()
+{
+}
+
+QString Room::address() const
+{
+       return iAddress;
+}
+
+QString Room::name() const
+{
+       return iName;
+}
+
+bool Room::equals( const Room &aOther ) const
+{
+       if ( iName == aOther.iName
+                 && iAddress == aOther.iAddress )
+       {
+               return true;
+       }
+       return false;
+}
+
+QString Room::toString() const
+{
+       QString roomToString = QString( "[Room: name:%1 address:%2 ]" )
+                                    .arg( iName )
+                                    .arg( iAddress );
+
+       return roomToString;
+}
+
+bool Room::caseInsensitiveLessThan( const Room *aRoom1, const Room *aRoom2 )
+{
+       return aRoom1->iName.toLower() < aRoom2->iName.toLower();
+}
diff --git a/src/Domain/Room.h b/src/Domain/Room.h
new file mode 100644 (file)
index 0000000..2f6d8f4
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef ROOM_H_
+#define ROOM_H_
+
+#include <QString>
+
+//! Domain class. Describe a meeting room resource on Microsoft Exchange Server 2007.
+/*!
+ * Domain class. Describe a meeting room resource on Microsoft Exchange Server 2007.
+ */
+class Room
+{
+public:
+       //! Enumeration of the status of the room.
+       /*!
+        * Enumeration of the status of the room. The room instance can have one of the two states.
+        */
+       enum Status
+       {
+               BusyStatus, /*!< The room is reserved. */
+               FreeStatus  /*!< The room is free. */
+       };
+
+public:
+       //! Constructor.
+       /*!
+        * Constructor to initialize a Room instance.
+        * \param aName The name of the meeting room.
+        * \param aAddress The mail address of the meeting room.
+        */
+       Room( const QString &aName, const QString &aAddress );
+       //! Destructor.
+       virtual ~Room();
+
+       //! Gets the name of the room.
+       /*!
+        * Gets the name of the room.
+        * \return The string containing the name.
+        */
+       QString name() const;
+       //! Gets the address of the room.
+       /*!
+        * Gets the address of the room.
+        * \return The string containing the address.
+        */
+       QString address() const;
+       //! Checks if two objects are equal.
+       /*!
+        * Checks if the another same type object is equal to the current instance.
+        * \param *aOther The pointer to another Room class instance.
+        * \return TRUE if equals; otherwise, FALSE.
+        */
+       bool equals( const Room &aOther ) const;
+       //! Makes a string to identify a room.
+       /*!
+        * Makes one string of the name and the address of the room.
+        * \return The string containing the name and address of the room.
+        */
+       QString toString() const;
+       //! Method to compare equalness of two rooms.
+       /*!
+        * Compares if two rooms are equal. Is not case sensitive.
+        * \param *aRoom1 A Pointer to the first room class instance.
+        * \param *aRoom2 A Pointer to the second room class instance.
+        * \return The string containing the name and address of the room.
+        */
+       static bool caseInsensitiveLessThan( const Room *aRoom1, const Room *aRoom2 );
+
+private:
+       //! The name for the room in this instance.
+       QString iName;
+       //! The address for the room in this instance.
+       QString iAddress;
+
+};
+
+#endif /*ROOM_H_*/
diff --git a/src/IO/Communication/Communication.cpp b/src/IO/Communication/Communication.cpp
new file mode 100644 (file)
index 0000000..82b847e
--- /dev/null
@@ -0,0 +1,114 @@
+#include "Communication.h"
+#include "ConnectionSettings.h"
+#include <QAuthenticator>
+
+Communication::Communication( const ConnectionSettings &aConnection ) :
+       iCurrentRequest(0),
+       iAuthFailCount(0)
+{
+       iConnectionSettings = new ConnectionSettings( aConnection );
+
+       iHttp = new QHttp( iConnectionSettings->serverUrl().toString(), QHttp::ConnectionModeHttps );
+       iResponse = new QByteArray();
+
+       connect( iHttp,
+                        SIGNAL( readyRead( const QHttpResponseHeader& ) ),
+                        this,
+                        SLOT( processResponse( const QHttpResponseHeader& ) )
+                       );
+       connect( iHttp,
+                        SIGNAL( requestStarted( int ) ),
+                        this,
+                        SLOT( handleRequestStarted( int ) )
+                       );
+       connect( iHttp,
+                        SIGNAL( requestFinished( int, bool ) ),
+                        this,
+                        SLOT( handleResults( int, bool ) )
+                       );
+       connect( iHttp,
+                        SIGNAL( dataReadProgress( int, int ) ),
+                        this,
+                        SLOT( handleReadProgress( int, int ) )
+                       );
+       connect( iHttp,
+                        SIGNAL( authenticationRequired( const QString&, quint16, QAuthenticator* ) ),
+                        this,
+                        SLOT( handleAuthentication( const QString&, quint16, QAuthenticator* ) ) );
+       connect( iHttp,
+                        SIGNAL( sslErrors( const QList<QSslError>& ) ),
+                        iHttp,
+                        SLOT( ignoreSslErrors() )/*this, SLOT( notifySsl( const QList<QSslError>& ) )*/
+                       );
+}
+
+Communication::~Communication()
+{
+       delete iConnectionSettings;
+       delete iHttp;
+       delete iResponse;
+}
+
+void Communication::processResponse( const QHttpResponseHeader& aHeader )
+{
+       if ( aHeader.statusCode() == 200 )
+       {
+               iResponse->append( iHttp->readAll() );
+       }
+}
+
+void Communication::handleRequestStarted( int aRequestId )
+{
+       if( aRequestId != 0 && iCurrentRequest != 0 &&
+           aRequestId == iCurrentRequest )
+       {
+               emit requestStarted( iCurrentRequest ); 
+       }
+}
+
+void Communication::handleResults( int aId, bool /*aError*/ )
+{
+       if( aId == iCurrentRequest )
+       {
+               iCurrentRequest = 0;
+               emit requestFinished( aId, iHttp->error() );
+       }
+}
+
+void Communication::handleAuthentication( const QString& /*aHost*/, quint16 /*aPort*/, QAuthenticator* aAuthenticator )
+{
+       aAuthenticator->setPassword( iConnectionSettings->password() );
+       aAuthenticator->setUser( iConnectionSettings->username() );
+       iAuthFailCount++;
+       if( iAuthFailCount > 1 )
+       {
+               iHttp->abort();
+       }
+}
+
+int Communication::request( const QString &aCommand, const QByteArray &aContent )
+{
+       //TODO: This is just temporarily here to implement multiple request support     
+       if( iCurrentRequest )
+               return 0;
+       QHttpRequestHeader header( QString( "POST" ), QString( "/ews/exchange.asmx" ) );
+       header.setValue( "Host", iConnectionSettings->serverUrl().toString() );
+       QString command = aCommand;
+       header.setContentType( command );
+
+       iAuthFailCount = 0;
+       iResponse->clear();
+       iCurrentRequest = iHttp->request( header, aContent );
+       
+       return iCurrentRequest;
+}
+
+const QByteArray& Communication::response( int /*aRequestId*/ )
+{
+       return *iResponse;
+}
+
+void Communication::handleReadProgress( int aDone, int aTotal )
+{
+       emit readProgress( iCurrentRequest, aDone, aTotal );
+}
diff --git a/src/IO/Communication/Communication.h b/src/IO/Communication/Communication.h
new file mode 100644 (file)
index 0000000..9fd8523
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef COMMUNICATION_H_
+#define COMMUNICATION_H_
+
+#include <QObject>
+#include <QHttp>
+
+class QByteArray;
+class ConnectionSettings;
+
+//! Class for handling HTTP requests and responses.
+/*!
+ *  This class uses the QHttp class to make HTTP requests. HTTP responses are
+ *  returned as QByteArray.
+ * 
+ *  NOTE! Currently this class does NOT support multiple simultaneuos requests.
+ */
+class Communication : public QObject
+{
+       Q_OBJECT
+
+public:
+       //! Constructor.
+       /*! 
+        *  \param aConnection Reference to ConnectionSettings which holds
+        *  the server to connect to and authentication information.
+       */
+       Communication( const ConnectionSettings &aConnection );
+       
+       virtual ~Communication();
+       //! Returns the response of a request identified by aRequestId.
+       /*! 
+        *  NOTE! Currently the last request response is returned as the multiple
+        *  request support is not implemented.
+        *  \param aRequestId Request id number.
+       */
+       const QByteArray& response( int aRequestId );
+
+       //! Makes a HTTP request to the server defined in the constructor.
+       /*! 
+        *  Returns a request id number if successful, otherwise zero.
+        *  \param aCommand Content type string of the HTTP header.
+        *  \param aContent Content body of the HTTP POST request.
+       */
+       int request( const QString &aCommand, const QByteArray &aContent );
+
+signals:
+       //! Emitted when a request ongoing. Reports the bytes read from the server.
+       /*! 
+       *   \param aRequestId Request id number.
+       *   \param aDone Bytes read from the server.
+       *   \param aTotal Bytes total of the response.
+       */
+       void readProgress( int aRequestId, int aDone, int aTotal );
+       //! Emitted when a request is started.
+       /*! 
+       *   \param aRequestId Request id number.
+       */
+       void requestStarted( int aRequestId );
+       //! Emitted when a request is finished.
+       /*! 
+       *   \param aRequestId Request id number.
+       *   \param aError Error code of the request finished.
+       */
+       void requestFinished( int aRequestId, QHttp::Error aError );
+
+protected slots:
+       //! Connected to QHttp::readyRead to read the response buffer.
+       void processResponse( const QHttpResponseHeader& aHeader );
+       //! Connected to QHttp::authenticationRequired to provide the user name and password defined in ConnectionSettings
+       void handleAuthentication( const QString& aHost, quint16 aPort, QAuthenticator* aAuthenticator );
+       //! Connected to QHttp::requestFinished 
+       void handleResults( int aId, bool aError );
+       //! Connected to QHttp::requestStarted
+       void handleRequestStarted( int aRequestId );
+       //! Connected to QHttp::dataReadProgress
+       void handleReadProgress( int aDone, int aTotal );
+
+private:
+       /*!
+        * Instance of Connection settings of the communication
+       */
+       ConnectionSettings *iConnectionSettings;
+       /*!
+        * Instance of QHttp
+       */
+       QHttp* iHttp;
+       /*!
+        * Response buffer
+       */
+       QByteArray* iResponse;
+       /*!
+        * ID number of a request currently ongoing
+       */
+       int iCurrentRequest;
+       /*!
+        * Counter how many times auhentication was failed to the server
+       */
+       int iAuthFailCount;
+};
+
+#endif /*COMMUNICATION_H_*/
diff --git a/src/IO/Communication/CommunicationManager.cpp b/src/IO/Communication/CommunicationManager.cpp
new file mode 100644 (file)
index 0000000..4212f68
--- /dev/null
@@ -0,0 +1,192 @@
+#include "CommunicationManager.h"
+#include "Communication.h"
+#include "ConnectionSettings.h"
+#include "Meeting.h"
+#include "Room.h"
+#include <QDateTime>
+#include <QDomDocument>
+#include <QDebug>
+
+static const int ERROR_BASE=100;
+
+CommunicationManager::CommunicationManager( const ConnectionSettings &aConnection )
+{
+       iConnectionSettings = new ConnectionSettings( aConnection );
+       iModifyingCommunication = NULL;
+       iFetchingCommunication = new Communication( aConnection );
+
+       if ( iFetchingCommunication )
+       {
+               connect( iFetchingCommunication,
+                                SIGNAL( readProgress( int, int, int ) ),
+                                this,
+                                SLOT( readProgress( int, int, int ) )
+                               );
+               connect( iFetchingCommunication,
+                                SIGNAL( requestFinished( int, QHttp::Error ) ),
+                                this,
+                                SLOT( requestFinished( int, QHttp::Error ) )
+                               );
+       }
+}
+
+CommunicationManager::~CommunicationManager()
+{
+       delete iConnectionSettings;
+       delete iModifyingCommunication;
+       delete iFetchingCommunication;
+       while ( !iMeetings.isEmpty() )
+               delete iMeetings.takeFirst();
+}
+
+void CommunicationManager::fetchMeetings( const QDateTime &aFrom, const QDateTime &aUntil, const Room &aIn )
+{
+       ReqMsgGetUserAvailability msg;
+       msg.setTimeZone();
+       msg.setTimeWindow( aFrom, aUntil );
+       msg.addUser( aIn.address() );
+               
+       int id = iFetchingCommunication->request( msg.getContentTypeForHeader(), msg.getMessage() );
+       qDebug() << "CommunicationManager::fetchMeetings: id: " << id;
+       if( id )
+       {
+               addRequest( GetUserAvailability, id );
+               iRequestInfos.first()->room = new Room( aIn );
+       }
+}
+
+void CommunicationManager::getSecondaryIdForMeeting( Meeting &aMeeting )
+{
+       ReqMsgConvertMeetingId msg( aMeeting.primaryId(), aMeeting.room().address() );
+       
+       QByteArray arr = msg.getMessage();
+
+       int id = iFetchingCommunication->request( msg.getContentTypeForHeader(), arr );
+       qDebug() << "CommunicationManager::getSecondaryIdForMeeting: id: " << id;
+       if( id )
+       {
+               addRequest( ConvertId, id );
+               iRequestInfos.first()->meeting = &aMeeting;
+       }
+}
+
+void CommunicationManager::fetchMeetingDetails( Meeting& aMeeting )
+{
+       if( aMeeting.detailsAvailable() )
+       {
+               emit meetingDetailsFetched( aMeeting );
+               return;
+       }
+       if( aMeeting.secondaryId().isEmpty() )
+       {
+               getSecondaryIdForMeeting( aMeeting );
+       }
+       else
+       {
+               getMeetingDetails( aMeeting );
+       }
+}
+
+void CommunicationManager::getMeetingDetails( Meeting &aMeeting )
+{
+       ReqMsgGetCalendarItem msg( aMeeting.secondaryId() );
+       
+       QByteArray arr = msg.getMessage();
+       
+       int id = iFetchingCommunication->request( msg.getContentTypeForHeader(), arr );
+       qDebug() << "CommunicationManager::getMeetingDetails: id: " << id;
+       if( id )
+       {
+               addRequest( GetCalendarItem, id );
+               iRequestInfos.first()->meeting = &aMeeting;
+       }
+}
+
+void CommunicationManager::requestFinished( int aRequestId, QHttp::Error aError )
+{
+       RequestData* rd = takeRequest( aRequestId );
+       qDebug() << "CommunicationManager::requestFinished: id: " << aRequestId << " error: " << (int)aError;
+
+       if( aError != QHttp::NoError || rd == NULL )
+       {
+               int err = (int)aError;
+               if( rd == NULL )
+                       err = 10;
+               delete rd;
+               emit error( ERROR_BASE+(int)err, CommunicationManager::FetchingCommunication );
+               return;
+       }
+
+       const QByteArray& response = iFetchingCommunication->response( aRequestId );
+
+       switch( rd->type )
+       {
+       case GetUserAvailability:
+               {
+               ResMsgGetUserAvailability msg( response );
+       
+               while ( !iMeetings.isEmpty() )
+                       delete iMeetings.takeFirst();
+       
+               int err = msg.getMeetingsFromResponse( iMeetings, *(rd->room) );
+               if( err )
+                       emit error( ERROR_BASE+8, CommunicationManager::FetchingCommunication );
+               else
+                       emit meetingsFetched( iMeetings );
+               break;
+               }
+       case ConvertId:
+               {
+               ResponseMessage msg( response );
+               QString id = msg.getNodeValue( QString( "Id" ),
+                                                                          QDomNode::AttributeNode,
+                                                                          QString( "AlternateId" ) );
+               qDebug( "ID IS: %s", id.toStdString().data() );
+               rd->meeting->setSecondaryId( id );
+               getMeetingDetails( *(rd->meeting) );
+               break;
+               }
+       case GetCalendarItem:
+               {
+               ResMsgGetCalendarItem msg( response );
+               int err = msg.getMeetingDetailsFromResponse( *(rd->meeting) );
+               if( err )
+                       emit error( ERROR_BASE+9, CommunicationManager::FetchingCommunication );
+               else
+                       emit meetingDetailsFetched( *(rd->meeting) );
+               break;
+               }
+       }
+       delete rd;
+}
+
+void CommunicationManager::readProgress( int /*aRequestId*/, int aDone, int aTotal )
+{
+       emit readProgress( aDone, aTotal, CommunicationManager::FetchingCommunication );
+}
+
+void CommunicationManager::addRequest( RequestType aType, int aRequestId )
+{
+       RequestData* rd = new RequestData( aType, aRequestId );
+       iRequestInfos.append( rd );
+}
+
+CommunicationManager::RequestData* CommunicationManager::takeRequest( int aRequestId )
+{
+       if( aRequestId == 0 )
+               return NULL;
+
+       for( int i = iRequestInfos.count() - 1; i >= 0 ; i-- )
+       {
+               struct RequestData* rd = iRequestInfos[i];
+               if( rd->requestId == aRequestId )
+               {
+                       iRequestInfos.removeAt( i );
+                       return rd;
+               }
+       }
+       return NULL;
+}
+
+
+
diff --git a/src/IO/Communication/CommunicationManager.h b/src/IO/Communication/CommunicationManager.h
new file mode 100644 (file)
index 0000000..d1ded78
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef COMMUNICATIONMANAGER_H_
+#define COMMUNICATIONMANAGER_H_
+
+#include <QObject>
+#include <QList>
+#include <QDateTime>
+#include "Communication.h"
+#include "Room.h"
+#include "MessagingUtils.h"
+
+class ConnectionSettings;
+class Meeting;
+
+//! Responsible for Exchange server communication and request encoding and response parsing.
+/*!
+ *  CommunicationManager holds two connections to the Exchange server:
+ *  Fetching and modifying connection. Fetching connetion is read only connection
+ *  which has static authentication information defined in the application configuration.
+ *  The modifying connection's authentication information varies, according to the user interface.
+ * 
+ *  NOTE! Currently Modifying connection is NOT implemented.
+ */
+class CommunicationManager : public QObject
+{
+       Q_OBJECT
+
+public:
+       enum CommunicationType
+       {
+               FetchingCommunication,
+               ModifyingCommunication
+       };
+
+public:
+       //! Constructor.
+       /*! 
+        *  \param aConnection Reference to the fetching ConnectionSettings.
+       */
+       CommunicationManager( const ConnectionSettings &aConnection );
+       virtual ~CommunicationManager();
+       //! Starts fetching meetings. Meetings are returned by the meetingsFetched signal.
+       /*! 
+        *  Calls the MS Exchange GetUserAvailability WebService method. 
+        *  \param aFrom QDateTime to start searching from.
+        *  \param aUntil QDateTime to search meetings until.
+        *  \param aIn Meeting room meetings are searched.
+       */
+       void fetchMeetings( const QDateTime &aFrom, const QDateTime &aUntil, const Room &aIn );
+       //! Starts fetching a meeting details. Details are returned by the meetingDetailsFetched signal.
+       /*! 
+        *  \param aMeeting A meeting the detailed information is wanted.
+       */
+       void fetchMeetingDetails( Meeting &aMeeting );
+/* Not supported member functions which are using the modifying communication
+       void setModifyCredentials( const QString &aUsername, const QString &aPassword ) {};
+       void createMeeting( const Meeting &aMeeting ) {};
+       void updateMeeting( const Meeting &aMeeting ) {};
+       void deleteMeeting( const Meeting &aMeeting ) {};
+*/
+
+signals:
+       //! Emitted when an error happens. Error could be QHttp or SOAP related.
+       /*! 
+       *   \param aCode An error code defined by CommunicationManager.
+       *   \param aType FetchingCommunication or ModifyingCommunication.
+       */
+       void error( int aCode, CommunicationManager::CommunicationType aType );
+       //! Emitted when a http request is ongoing. Reports the bytes read from the server.
+       /*! 
+       *   \param aDone Bytes read from the server.
+       *   \param aTotal Bytes total of the response.
+       *   \param aType FetchingCommunication or ModifyingCommunication.
+       */
+       void readProgress( int aDone, int aTotal, CommunicationManager::CommunicationType aType );
+       //! Emitted when meetings are fetched.
+       /*! 
+       *   \param aMeetings Meetings found according to the search criteria.
+       */
+       void meetingsFetched( const QList<Meeting*> &aMeetings );
+       //! Emitted when meeting details are fetched.
+       /*! 
+       *   \param aDetailedMeeting Meeting which contains detailed information.
+       */
+       void meetingDetailsFetched( Meeting &aDetailedMeeting );
+
+protected slots:
+       //! Connected to Communication::requestFinished.
+       void requestFinished( int aRequestId, QHttp::Error aError );
+       //! Connected to Communication::readProgress.
+       void readProgress( int aRequestId, int aDone, int aTotal );
+       
+protected:
+       //! Gets the secondary id number of a meeting.
+       /*! 
+        *  Calls the MS Exchange ConvertId WebService method. Converts primary id
+        *  number to secondary id number.
+        *  \param aMeeting A meeting which contains primaryId number.
+       */
+       void getSecondaryIdForMeeting( Meeting &aMeeting );
+       //! Gets the details of a meeting.
+       /*! 
+        *  Calls the MS Exchange GetCalendarItem WebService method.
+        *  \param aMeeting A meeting the detailed information is wanted.
+       */
+       void getMeetingDetails( Meeting &aMeeting );
+       
+       /*! 
+        *  Lists the WebService methods known by the CommunicationManager.
+       */
+       enum RequestType
+       {
+               GetUserAvailability = 1,
+               ConvertId,
+               GetCalendarItem
+       };
+       //! Internal data structure which contains data about requests made to Exchange server.
+       class RequestData
+       {
+       public:
+               RequestData( RequestType aType, int aRequestId ) : 
+                       type( aType ), requestId( aRequestId ), room( NULL ), meeting( NULL ) {};
+               ~RequestData()
+               {
+                       if( type == GetUserAvailability )
+                               delete room;
+               };
+               //! Holds one of the enum RequestType value
+               RequestType type;
+               //! Request ID number returned by the Communication::request
+               int requestId;
+               //! Pointer to a Room related to this request. NULL by default. Owned.
+               Room* room;
+               //! Pointer to a Meeting related to this request. Not owned.
+               Meeting* meeting;
+       };
+       //! Adds a request to the iRequestInfos list.
+       /*! 
+        *  \param aType One of the enum RequestType value.
+        *  \param aRequestId Request ID number returned by the Communication::request
+       */
+       void addRequest( RequestType aType, int aRequestId );
+       //! Takes RequestData off from the iRequestInfos list.
+       /*! 
+        *  Returns a pointer to RequestData data structure. Removes RequestData from
+        *  the iRequestInfos list.
+        *  \param aRequestId Request ID number returned by the Communication::request
+       */
+       RequestData* takeRequest( int aRequestId );
+       
+private:
+       //! Instance of Connection settings of the fetching communication
+       ConnectionSettings *iConnectionSettings;
+       //! Instance of the fetching communication
+       Communication* iFetchingCommunication;
+       //! Instance of the modifying communication
+       Communication* iModifyingCommunication;
+       //! Temporary list which holds the lastest meetings fetched
+       QList<Meeting*> iMeetings;
+       //! Additional information about requests made to the Exchange server
+       QList<RequestData*> iRequestInfos;
+};
+
+#endif /*COMMUNICATIONMANAGER_H_*/
diff --git a/src/IO/Communication/MessagingUtils.cpp b/src/IO/Communication/MessagingUtils.cpp
new file mode 100644 (file)
index 0000000..0f6e63e
--- /dev/null
@@ -0,0 +1,1125 @@
+#include <QUrl>
+
+#include "MessagingUtils.h"
+#include "Meeting.h"
+#include "Configuration.h"
+
+/*
+ * BaseMessage class functions
+*/
+BaseMessage::BaseMessage()
+{
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::BaseMessage" );
+#endif
+       iMessage = new QDomDocument();
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::BaseMessage end" );
+#endif
+}
+
+BaseMessage::~BaseMessage()
+{
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::~BaseMessage" );
+#endif
+       if( iMessage )
+               {
+               delete iMessage;
+               iMessage = 0;
+               }
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::~BaseMessage end" );
+#endif
+}
+
+QList<QDomNode> BaseMessage::getNodesByName( const QString& aNodeName, const QString& aParentName, QDomNode* aRootNode )
+{
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::getNodesByName" );
+#endif
+       
+       //TODO: Add implementation for attribute search
+       
+       QDomNodeList list;
+       QList<QDomNode> specList;
+       
+       list = ( aRootNode ) ? aRootNode->toElement().elementsByTagName( aNodeName ) : iMessage->elementsByTagName( aNodeName );
+
+       for( int i=0; i<list.count(); i++ )
+       {
+               if( aParentName != QString::null )
+               {
+               if( !list.item( i ).parentNode().isNull() && list.item( i ).parentNode().isElement() && list.item( i ).parentNode().toElement().tagName().compare( aParentName ) == 0 )
+                       specList.append( list.item( i ) );
+               }
+               else
+                       specList.append( list.item( i ) );
+       }
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::getNodesByName end" );
+#endif         
+       return specList;
+}
+
+QDomNode BaseMessage::getNodeFromDocument( const QString& aNodeName,
+                                                               QDomNode::NodeType aNodeType,
+                                                               const QString& aParentName,
+                                                               int aIndex,
+                                                               QDomNode* aRootNode )
+{
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::getNodeFromDocument" );
+#endif
+       QDomNode node;
+       if( aNodeType == QDomNode::ElementNode )
+               node = getElementFromDocument( aNodeName, aParentName, aIndex, aRootNode );
+       else if( aNodeType == QDomNode::AttributeNode )
+               node = getAttributeFromDocument( aNodeName, aParentName, aIndex, aRootNode );
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::getNodeFromDocument end" );
+#endif
+       return node;
+}
+
+QDomNode BaseMessage::getAttributeFromDocument( const QString& aAttributeName,
+                                                               const QString& aParentName,
+                                                               int aIndex,
+                                                               QDomNode* aRootNode )
+{
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::getAttributeFromDocument" );
+#endif
+
+       QDomNode root;
+       QDomNode node;
+       QDomNode parent;
+       
+       root = ( !aRootNode ) ? iMessage->documentElement() : *aRootNode;
+       if( root.isNull() )
+               {
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::getAttributeFromDocument : RootNode is NULL." );
+#endif         
+               return node;
+               }
+
+       if( aParentName != QString::null )
+       {
+               if( root.isElement() )
+               {
+                       QDomNodeList list = root.toElement().elementsByTagName( aParentName );
+                       if( list.count() > 0 ) parent = list.item( 0 );
+               }
+       }
+       
+       QDomNamedNodeMap attrs = parent.attributes();
+       
+       int count = attrs.count();
+       if( count==0 || aIndex >= count || !attrs.contains( aAttributeName ) ) return root;
+
+       QList<QDomAttr> list;
+
+       for( int i=0; i<count; i++ )
+       {
+               QDomAttr attr = attrs.item( i ).toAttr();
+
+               if( attr.name().compare( aAttributeName ) == 0 || attr.localName().compare( aAttributeName ) == 0 )
+               {
+                       if( aParentName != QString::null && ( attr.ownerElement().tagName().compare( aParentName ) == 0 || attr.ownerElement().localName().compare( aParentName ) == 0 ))
+                       {
+                               list.append( attr );
+                       }
+                       else
+                               list.append( attr );
+               }
+
+       }
+
+       if( list.count() > 0 )
+               node = list.at( aIndex );
+
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::getAttributeFromDocument end." );
+#endif 
+       
+       return node;
+}
+
+QDomNode BaseMessage::getElementFromDocument( const QString& aElementName,
+                                                               const QString& aParentName,
+                                                               int aIndex,
+                                                               QDomNode* aRootNode )
+{
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::getElementFromDocument" );
+#endif
+               QDomNode node;
+               QDomNodeList elems;
+
+               if( !aRootNode )
+               {
+               elems = iMessage->elementsByTagName( aElementName );
+               }
+               else
+               {
+               elems = aRootNode->toElement().elementsByTagName( aElementName );
+               }
+
+               int count = elems.count();
+               if( count == 0 || aIndex >= count )
+               { 
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::getElementFromDocument : No Elements found." );
+#endif                 
+                       return node; //no elements found
+               }
+
+               QList<QDomElement> list;
+
+               for( int i=0; i<count; i++ )
+               {
+                       QDomElement elem = elems.item( i ).toElement();
+                       if( elem.tagName().compare( aElementName ) == 0 || elem.localName().compare( aElementName ) == 0 )
+                       {
+                               if( aParentName != QString::null )
+                               {
+                                       if( !elem.parentNode().isNull() )
+                                       {
+                                               if( elem.parentNode().toElement().tagName().compare( aParentName ) == 0 || elem.parentNode().toElement().tagName().compare( aParentName ) == 0 )
+                                                       list.append( elem );
+                                       }
+                               }
+                               else
+                                       list.append( elem );
+                       }
+
+               }
+
+               if( list.count() > 0 )
+                       node = list.at( aIndex );
+
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::getElementFromDocument end" );
+#endif         
+               return node;
+}
+
+bool BaseMessage::matchName( const QDomNode& aNode, const QString& aName )
+{
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::matchName" );
+#endif
+       if( aNode.isElement() )
+       {
+               if( aNode.toElement().tagName().toLower().compare( aName.toLower() ) == 0
+                               || aNode.localName().toLower().compare( aName.toLower() ) == 0 )
+               {
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::matchName end" );
+#endif                 
+                       return true;
+               }
+       }
+       else if( aNode.isAttr() )
+       {
+               if( aNode.toAttr().name().toLower().compare( aName.toLower() ) == 0
+                               || aNode.localName().toLower().compare( aName.toLower() ) == 0 )
+               {
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::matchName end" );
+#endif                 
+                       return true;
+               }
+       }
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::matchName : No match." );
+#endif 
+       return false;
+}
+
+QByteArray BaseMessage::getMessage()
+{
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::getMessage" );
+#endif
+       QByteArray msg;
+       if( iMessage )
+       {
+               msg.append( iMessage->toByteArray() );
+       }
+#ifdef MU_DEBUG
+       qDebug( "BaseMessage::getMessage end" );
+#endif 
+       return msg;
+}
+
+/*
+ * RequestMessage class functions
+*/
+RequestMessage::RequestMessage( RequestCommandId aCommandId ) : iCurrCmd( aCommandId )
+{
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::RequestMessage" );
+#endif
+       createEnvelopeBase();
+
+       if( aCommandId != ReqCmdNoCommand )
+       {
+               createMessageStructure( aCommandId );
+       }
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::RequestMessage end" );
+#endif
+}
+
+RequestMessage::RequestMessage( const QString& /*aFileName*/ )
+{
+       //createEnvelopeBase();
+       //TODO: read operation structures from a file
+}
+
+int RequestMessage::addNode( const QDomNode& aNode, QDomNode::NodeType aNodeType, const QString& aParentName, int aIndex, QDomNode* aRootNode )
+{
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::addNode" );
+#endif
+
+       if( !iMessage )
+       {
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::addNode : iMessage is NULL." );
+#endif 
+               return MsgErrSomeError;
+       }
+
+       int err = MsgErrNoError;
+
+       if( aNodeType == QDomNode::ElementNode && aNode.isElement() )
+       {
+               if( aParentName == QString::null )
+               {
+                       if( !aRootNode )
+                       iMessage->appendChild( aNode );
+                       else
+                       aRootNode->appendChild( aNode );
+               }
+               else
+               {
+                       QDomNodeList list = ( aRootNode ) ? aRootNode->toElement().elementsByTagName( aParentName ) : iMessage->elementsByTagName( aParentName );
+                               
+                       if( list.count() == 0 || aIndex >= list.count() ) err = MsgErrSomeError;
+                       else
+                       {
+                               QDomElement node = list.at( aIndex ).toElement();
+                               node.appendChild( aNode );
+                       }
+               }
+       }
+       else if( aNodeType == QDomNode::AttributeNode && aNode.isAttr() )
+       {
+               if( aParentName != QString::null )
+               {
+                       QDomNodeList list = ( aRootNode ) ? aRootNode->toElement().elementsByTagName( aParentName ) : iMessage->elementsByTagName( aParentName );
+                               
+                       if( list.count() == 0 || aIndex >= list.count() ) err = MsgErrSomeError;
+                       else
+                       {
+                               QDomElement node = list.at( aIndex ).toElement();
+                               node.setAttributeNode( aNode.toAttr() );
+                       }
+               }
+               else
+                       err = MsgErrSomeError; //Attribute must have a parent specified
+       }
+       else
+               err = MsgErrSomeError;
+
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::addNode end : err=%d", err );
+#endif         
+       return err;
+}
+
+int RequestMessage::setNodeValue( const QString& aNodeName, const QString& aValue, QDomNode::NodeType aNodeType, const QString& aParentName, int aIndex, QDomNode* aRootNode )
+{
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::setNodeValue" );
+#endif
+
+       QDomNode node = getNodeFromDocument( aNodeName, aNodeType, aParentName, aIndex, aRootNode );
+       if( node.isNull() || !iMessage )
+               {
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::setNodeValue : Node is NULL or iMessage is NULL." );
+#endif         
+               return MsgErrSomeError;
+               }
+
+       int err = MsgErrNoError;
+
+       if( node.isElement() )
+       {
+               node.appendChild( iMessage->createTextNode( aValue ) );
+       }
+       else if( node.isAttr() )
+               node.toAttr().setValue( aValue );
+       else
+               err = MsgErrSomeError;
+
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::setNodeValue end : err=%d", err );
+#endif 
+       return err;
+}
+
+int RequestMessage::createEnvelopeBase()
+{
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::createEnvelopeBase" );
+#endif
+       if( iMessage )
+               {
+               delete iMessage;
+               iMessage = 0;
+               }
+
+       iMessage = new QDomDocument();
+
+       int size = sizeof( reqCmdArrayEnvelopeBase ) / sizeof( MessageBodyElement );
+       int err = MsgErrNoError;
+
+       QDomNode base = constructArrayToNode( reqCmdArrayEnvelopeBase, size );
+
+       if( !base.isNull() )
+               err = addNode( base );
+       else err = MsgErrSomeError;
+
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::createEnvelopeBase end : err=%d", err );
+#endif         
+       return err;
+}
+
+QString RequestMessage::getContentTypeForHeader( RequestCommandId aCommandId )
+{
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::getContentTypeForHeader" );
+#endif
+       QString contentType( QString::null );
+
+       RequestCommandId cmd = ( aCommandId == ReqCmdNoCommand ) ? iCurrCmd : aCommandId;
+
+       if( cmd != ReqCmdNoCommand )
+       {
+               QString operation( QString::null );
+               switch( cmd )
+               {
+               //Used commands
+               case ReqCmdGetUserAvailability : { operation = "GetUserAvailability"; } break;
+               case ReqCmdConvertId : { operation = "ConvertId"; } break;
+               case ReqCmdGetItem : { operation = "GetItem"; } break;
+
+               //Currently unused operations
+
+               /*case ReqCmdAddDelegate : { operation = "AddDelegate"; } break;
+               case ReqCmdCopyFolder : { operation = "CopyFolder"; } break;
+               case ReqCmdCopyItem : { operation = "CopyItem"; } break;
+               case ReqCmdCreateAttachment : { operation = "CreateAttachment"; } break;
+               case ReqCmdCreateFolder : { operation = "CreateFolder"; } break;
+               case ReqCmdCreateItem : { operation = "CreateItem"; } break;
+               case ReqCmdCreateManagedFolder : { operation = "CreateManagedFolder"; } break;
+               case ReqCmdDeleteAttachment : { operation = "DeleteAttachment"; } break;
+               case ReqCmdDeleteFolder : { operation = "DeleteFolder"; } break;
+               case ReqCmdDeleteItem : { operation = "DeleteItem"; } break;
+               case ReqCmdExpandDL : { operation = "ExpandDL"; } break;
+               case ReqCmdFindFolder : { operation = "FindFolder"; } break;
+               case ReqCmdFindItem : { operation = "FindItem"; } break;
+               case ReqCmdGetAttachment : { operation = "GetAttachment"; } break;
+               case ReqCmdGetDelegate : { operation = "GetDelegate"; } break;
+               case ReqCmdGetEvents : { operation = "GetEvents"; } break;
+               case ReqCmdGetFolder : { operation = "GetFolder"; } break;
+               case ReqCmdGetUserOofSettings : { operation = "GetUserOofSettings"; } break;
+               case ReqCmdMoveFolder : { operation = "MoveFolder"; } break;
+               case ReqCmdMoveItem : { operation = "MoveItem"; } break;
+               case ReqCmdRemoveDelegate : { operation = "RemoveDelegate"; } break;
+               case ReqCmdResolveNames : { operation = "ResolveNames"; } break;
+               case ReqCmdSendItem : { operation = "SendItem"; } break;
+               case ReqCmdSetUserOofSettings : { operation = "SetUserOofSettings"; } break;
+               case ReqCmdSubscribe : { operation = "Subscribe"; } break;
+               case ReqCmdSyncFolderHierarchy : { operation = "SyncFolderHierarchy"; } break;
+               case ReqCmdSyncFolderItems : { operation = "SyncFolderItems"; } break;
+               case ReqCmdUnsubscribe : { operation = "Unsubscribe"; } break;
+               case ReqCmdUpdateDelegate : { operation = "UpdateDelegate"; } break;
+               case ReqCmdUpdateFolder : { operation = "UpdateFolder"; } break;
+               case ReqCmdUpdateItem : { operation = "UpdateItem"; } break;*/
+               default: break;
+               };
+
+               if( operation != QString::null )
+               {
+                       QString content( "text/xml; " );
+                       QString charset( "utf-8; " );
+                       contentType = QString( content + "charset=" + charset + "action=\"" + ACTION_URL + operation + "\"" );
+               }
+       }
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::getContentTypeForHeader end : contentType=%s", contentType.toStdString().data() );
+#endif         
+       return contentType;
+}
+
+int RequestMessage::createMessageStructure()
+{
+       return createMessageStructure( iCurrCmd );
+}
+
+int RequestMessage::createMessageStructure( RequestCommandId aCommandId )
+{
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::createMessageStructure" );
+#endif
+       if( !iMessage )
+       {
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::createMessageStructure : iMessage is NULL" );
+#endif         
+               return MsgErrSomeError;
+       }
+
+       //Should always be soap:Envelope or first element in envelopebase array
+       QDomNode last = iMessage->documentElement();
+
+       if( !matchName( last, reqCmdArrayEnvelopeBase[0].iElementName ) )
+       {
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::createMessageStructure : Document element is not valid SOAP envelope" );
+#endif         
+               return MsgErrSomeError;
+       }
+
+       QDomNode cmd;
+       int err = MsgErrNoError;
+
+       switch( aCommandId )
+       {
+       case ReqCmdGetUserAvailability : { cmd = constructArrayToNode( reqCmdArrayGetUserAvailability, sizeof( reqCmdArrayGetUserAvailability ) / sizeof( MessageBodyElement ) ); } break;
+       case ReqCmdConvertId : { cmd = constructArrayToNode( reqCmdArrayConvertId, sizeof( reqCmdArrayConvertId ) / sizeof( MessageBodyElement ) ); } break;
+       case ReqCmdGetItem : { cmd = constructArrayToNode( reqCmdArrayGetCalendarItem, sizeof( reqCmdArrayGetCalendarItem ) / sizeof( MessageBodyElement ) ); } break;
+       default: break;
+       };
+
+       if( cmd.isNull() ) err = MsgErrSomeError;
+       else{
+               err = addNode( cmd, QDomNode::ElementNode, reqCmdArrayEnvelopeBase[0].iElementName );
+       }
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::createMessageStructure end : err=%d", err );
+#endif 
+       return err;
+}
+
+QDomNode RequestMessage::constructArrayToNode( const MessageBodyElement* aArray, int aSize )
+{
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::constructArrayToNode" );
+#endif
+       QDomElement target; //final node to be returned
+
+       if( !iMessage || aSize == 0 )
+               {
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::constructArrayToNode : iMessage is NULL or aSize is 0." );
+#endif
+               return target;
+               }
+
+       QDomElement last; // last appended node
+
+       int currentLvl = 0; //current traversal level
+       int idx = 0;
+
+       //get the root
+       MessageBodyElement root = aArray[idx];
+       if( root.iNodeType != QDomNode::ElementNode || root.iTraversalLevel > 0 )
+       {
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::constructArrayToNode : Malformed message definition. Check array for faults." );
+#endif         
+               return target; //Root must be an element and on level 0
+       }
+       else
+       {
+               if( root.iNamespace != QString::null )
+               {
+                       //QString prefix = root.iNamespace
+                       target = iMessage->createElementNS( root.iNamespace, root.iElementName );
+               }
+               else
+               {
+                       target = iMessage->createElement( root.iElementName );
+               }
+               last = target;
+               idx++;
+       }
+
+       for( int i=idx; i<aSize; i++ )
+       {
+               MessageBodyElement element = aArray[i];
+
+               if( element.iNodeType == QDomNode::ElementNode )
+               {
+                       //Node is an element node
+                       QDomElement elem;
+                       if( element.iNamespace != QString::null )
+                       {
+                               elem = iMessage->createElementNS( element.iNamespace, element.iElementName );
+                       }
+                       else
+                       {
+                               elem = iMessage->createElement( element.iElementName );
+                       }
+                       if( element.iTraversalLevel == currentLvl )
+                       {
+                               if( currentLvl == 0 )
+                               {
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::constructArrayToNode : Malformed message definition. Check array for faults." );
+#endif                                                 
+                                       return target; //Only root can be at traversal level 0
+                               }
+                               else
+                               {
+                                       //Sibling to previous
+                                       if( !last.parentNode().isNull() )
+                                               last.parentNode().appendChild( elem );
+                                       else
+                                               {
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::constructArrayToNode : Malformed message definition. Check array for faults." );
+#endif 
+                                               return target; //malformed. if last has no parent, it's a rootnode
+                                               }
+                               }
+                       }
+                       else if( element.iTraversalLevel > currentLvl )
+                       {
+                               //check if node is child to previous
+                               //else there is something wrong in array representing the structure
+                               if( element.iTraversalLevel == currentLvl+1 )
+                               {
+                                       last.appendChild( elem );
+                               }
+                               else
+                               {
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::constructArrayToNode : Malformed message definition. Check array for faults." );
+#endif 
+                                       return target;
+                               }
+                       }
+                       else if( element.iTraversalLevel < currentLvl )
+                       {
+
+                               //Node is on more shallow level than previous
+                               //let's get it's parent
+                               int diff = currentLvl - element.iTraversalLevel;
+
+                               for( int j=0; j<diff; j++ )
+                               {
+                                       QDomNode temp = last.parentNode();
+                                       last = temp.toElement();
+                               }
+                               last.parentNode().appendChild( elem );
+                       }
+                       else
+                       {
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::constructArrayToNode : Malformed message definition. Check array for faults." );
+#endif                         
+                               //some undefined error
+                               return target;
+                       }
+
+                       last = elem;
+               }
+               else if( element.iNodeType == QDomNode::AttributeNode )
+               {
+                       //Node is an attribute node
+
+                       QDomAttr attr;
+                       if( element.iNamespace != QString::null )
+                                attr = iMessage->createAttributeNS( element.iNamespace, element.iElementName );
+                       else
+                                attr = iMessage->createAttribute( element.iElementName );
+
+                       if( element.iTraversalLevel == currentLvl )
+                       {
+                               last.setAttributeNode( attr );
+                       }
+                       else
+                       {
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::constructArrayToNode : Malformed message definition. Check array for faults." );
+#endif                                 
+                               //error in template array.
+                               //attributes for element must be specified right after element
+                               //and must have same traversalId
+                               return target;
+                       }
+               }
+               else
+               {
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::constructArrayToNode : Node type not supported." );
+#endif 
+                       //node type not supported
+                       return target;
+               }
+
+               currentLvl = element.iTraversalLevel;
+       }
+#ifdef MU_DEBUG
+       qDebug( "RequestMessage::constructArrayToNode : end" );
+#endif 
+       return target;
+}
+
+/*
+ * ResponseMessage class functions
+ */
+ResponseMessage::ResponseMessage()
+{
+#ifdef MU_DEBUG
+       qDebug( "ResponseMessage::ResponseMessage" );
+#endif
+       iMessage = new QDomDocument();
+#ifdef MU_DEBUG
+       qDebug( "ResponseMessage::ResponseMessage end" );
+#endif
+}
+
+ResponseMessage::ResponseMessage( const QByteArray& aData )
+{
+#ifdef MU_DEBUG
+       qDebug( "ResponseMessage::ResponseMessage" );
+#endif
+       iMessage->setContent( aData, true );
+#ifdef MU_DEBUG
+       qDebug( "ResponseMessage::ResponseMessage end" );
+#endif
+}
+
+QString ResponseMessage::getNodeValue( const QString& aNodeName, QDomNode::NodeType aNodeType, const QString& aParentName, int aIndex, QDomNode* aRootNode )
+{
+#ifdef MU_DEBUG
+       qDebug( "ResponseMessage::getNodeValue" );
+#endif 
+       QString value = QString::null;
+       QDomNode node = getNodeFromDocument( aNodeName, aNodeType, aParentName, aIndex, aRootNode );
+       if( !node.isNull() )
+       {
+               if( node.isElement() )
+                       value = node.toElement().text();
+               else if( node.isAttr() )
+                       value = node.toAttr().value();
+       }
+#ifdef MU_DEBUG
+       qDebug( "ResponseMessage::getNodeValue end" );
+#endif 
+       return value;   
+}
+
+bool ResponseMessage::hasErrors()
+{
+#ifdef MU_DEBUG
+       qDebug( "ResponseMessage::hasErrors" );
+#endif
+       if( !iMessage )
+               {
+#ifdef MU_DEBUG
+       qDebug( "ResponseMessage::hasErrors : iMessage is NULL." );
+#endif
+               return true;
+               }
+
+       QDomElement root = iMessage->documentElement();
+       bool err = false;
+
+       QString rootname = ( root.prefix() == QString::null ) ? root.tagName() : root.localName();
+       err = ( rootname.compare( QString( "Envelope" ) ) == 0 ) ? false : true;
+
+       QDomNodeList list = iMessage->elementsByTagName( QString( "m:ResponseCode" ) );
+       for( int i=0; i<list.count(); i++ )
+       {
+               if( list.item(i).nodeValue().compare( "NoError" ) != 0 )
+                       {
+                       err = true;
+                       }
+       }
+#ifdef MU_DEBUG
+       qDebug( "ResponseMessage::hasErrors end : err=%d", err );
+#endif 
+       return err;
+}
+
+/*
+ * ReqMsgGetUserAvailability class functions
+ */
+
+ReqMsgGetUserAvailability::ReqMsgGetUserAvailability() : RequestMessage( ReqCmdGetUserAvailability )
+{
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetUserAvailability::ReqMsgGetUserAvailability" );
+#endif
+       if( iMessage && iCurrCmd == ReqCmdGetUserAvailability )
+       {
+               setNodeValue( QString( "MergedFreeBusyIntervalInMinutes" ), QString::number( 60 ) );
+               setNodeValue( QString( "RequestedView" ), QString( "DetailedMerged" ) );
+       }
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetUserAvailability::ReqMsgGetUserAvailability end" );
+#endif 
+}
+
+int ReqMsgGetUserAvailability::addUser( const QString& aAddress, const QString& /*aAttendeeType*/, const QString& aExcludeConflicts )
+{
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetUserAvailability::addUser" );
+#endif
+       if( !iMessage || iCurrCmd != ReqCmdGetUserAvailability )
+       {
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetUserAvailability::addUser : iMessage is NULL or current command id is wrong" );
+#endif         
+               return MsgErrSomeError;
+       }
+
+       int err = MsgErrNoError;
+       int size = sizeof( reqCmdMailboxElement ) / sizeof( MessageBodyElement );
+
+       //Create mailbox data element
+       QDomNode mailbox = constructArrayToNode( reqCmdMailboxElement, size );
+       if( !mailbox.isNull() )
+       {
+               QDomNode email;
+
+               if( mailbox.hasChildNodes() )
+               {
+                       for ( QDomNode subnode = mailbox.firstChild(); !subnode.isNull(); subnode = subnode.nextSibling() )
+                       {
+                               qDebug( "subnode: %s", subnode.toElement().tagName().toStdString().data() );
+                               if( matchName( subnode, QString( "Email" ) ) )
+                                       {
+                                       email = subnode;
+                                       }
+                       }
+               }
+
+               setNodeValue( QString( "Address" ), aAddress, QDomNode::ElementNode, QString( "Email" ), 0, &email );
+               setNodeValue( QString( "AttendeeType" ), QString( "Required" ), QDomNode::ElementNode, QString( "MailboxData" ), 0, &mailbox );
+               setNodeValue( QString( "ExcludeConflicts" ), aExcludeConflicts, QDomNode::ElementNode, QString( "MailboxData" ), 0, &mailbox );
+
+               err = addNode( mailbox, QDomNode::ElementNode, QString( "MailboxDataArray" ) );
+       }
+       else
+               err = MsgErrSomeError;
+
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetUserAvailability::addUser end : err=%d", err );
+#endif 
+       return err;
+}
+
+int ReqMsgGetUserAvailability::setTimeWindow( const QDateTime& aStart, const QDateTime& aEnd )
+{
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetUserAvailability::setTimeWindow" );
+#endif
+       if( !iMessage || iCurrCmd != ReqCmdGetUserAvailability )
+       {
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetUserAvailability::setTimeWindow : iMessage is NULL or command id is wrong" );
+#endif         
+               return MsgErrSomeError;
+       }
+
+       int err = MsgErrNoError;
+
+       err = setNodeValue( QString( "StartTime" ), aStart.toString( Qt::ISODate ) );
+       err = setNodeValue( QString( "EndTime" ), aEnd.toString( Qt::ISODate ) );
+
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetUserAvailability::setTimeWindow end : err=%d", err );
+#endif         
+       return err;
+}
+
+int ReqMsgGetUserAvailability::setTimeZone()
+{
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetUserAvailability::setTimeZone" );
+#endif
+       if( !iMessage || iCurrCmd != ReqCmdGetUserAvailability )
+       {
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetUserAvailability::setTimeZone : iMessage is NULL or command id is wrong" );
+#endif         
+               return MsgErrSomeError;
+       }
+       int err = MsgErrNoError;
+       //TODO: timezone and daylight times to application configuration
+       setNodeValue( QString( "Bias" ), QString::number( -120 ), QDomNode::ElementNode, QString( "TimeZone" ) );
+       setNodeValue( QString( "Bias" ), QString::number( 0 ), QDomNode::ElementNode, QString( "StandardTime" ) );
+       setNodeValue( QString( "Time" ), QString( "03:00:00" ), QDomNode::ElementNode, QString( "StandardTime" ) );
+       setNodeValue( QString( "DayOrder" ), QString::number( 5 ), QDomNode::ElementNode, QString( "StandardTime" ) );
+       setNodeValue( QString( "Month" ), QString::number( 10 ), QDomNode::ElementNode, QString( "StandardTime" ) );
+       setNodeValue( QString( "DayOfWeek" ), QString( "Sunday" ), QDomNode::ElementNode, QString( "StandardTime" ) );
+       setNodeValue( QString( "Bias" ), QString::number( -60 ), QDomNode::ElementNode, QString( "DaylightTime" ) );
+       setNodeValue( QString( "Time" ), QString( "03:00:00" ), QDomNode::ElementNode, QString( "DaylightTime" ) );
+       setNodeValue( QString( "DayOrder" ), QString::number( 1 ), QDomNode::ElementNode, QString( "DaylightTime" ) );
+       setNodeValue( QString( "Month" ), QString::number( 4 ), QDomNode::ElementNode, QString( "DaylightTime" ) );
+       setNodeValue( QString( "DayOfWeek" ), QString( "Sunday" ), QDomNode::ElementNode, QString( "DaylightTime" ) );
+
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetUserAvailability::setTimeZone end : err=%d", err );
+#endif         
+       return err;
+}
+
+/*
+ * ReqMsgConvertMeetingId class functions
+ */
+ReqMsgConvertMeetingId::ReqMsgConvertMeetingId( const QString& aItemId, const QString& aMailbox )
+{
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgConvertMeetingId::ReqMsgConvertMeetingId" );
+#endif 
+       //For this class, we're not going to provide id for base class as parameter,
+       //because before content structure initialization, we must add SOAP header to envelope
+       iCurrCmd = ReqCmdConvertId;
+       
+       QDomNode header = constructArrayToNode( reqCmdArrayConvertIdHeader, sizeof( reqCmdArrayConvertIdHeader ) / sizeof( MessageBodyElement ) );
+       
+       if( !header.isNull() )
+       {
+               int err = addNode( header, QDomNode::ElementNode, reqCmdArrayEnvelopeBase[0].iElementName );
+
+               if( err == MsgErrNoError )
+               {
+               createMessageStructure( ReqCmdConvertId );
+               
+               if( aItemId != QString::null ) setItemId( aItemId );
+               if( aMailbox != QString::null ) setMailbox( aMailbox );
+               
+               setNodeValue( QString( "Version" ), QString( "Exchange2007_SP1" ), QDomNode::AttributeNode, QString( "RequestServerVersion" ) );
+               setNodeValue( QString( "DestinationFormat" ), QString( "EwsLegacyId" ), QDomNode::AttributeNode, QString( "ConvertId" ) );
+               setNodeValue( QString( "Format" ), QString( "HexEntryId" ), QDomNode::AttributeNode, QString( "AlternateId" ) );
+               }
+       }
+       //setNodeValue( QString( "xmlns:t" ), NS_T, QDomNode::AttributeNode, QString( "ConvertId" ) );
+       
+       //Must be added (for now at least) like this, because Envelope is initialized already, without attributes
+       /*QDomAttr attr = iMessage->createAttribute( QString( "xmlns:t" ) );
+       attr.setValue( NS_T );
+       addNode( attr, QDomNode::AttributeNode, QString( "Envelope" ) );
+       */
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgConvertMeetingId::ReqMsgConvertMeetingId end" );
+#endif         
+}
+
+int ReqMsgConvertMeetingId::setItemId( const QString& aItemId )
+{
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgConvertMeetingId::setItemId" );
+#endif 
+       int err = setNodeValue( QString( "Id" ), aItemId, QDomNode::AttributeNode, QString( "AlternateId" ) );
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgConvertMeetingId::setItemId end : err=%d", err );
+#endif 
+       return err;
+}
+
+int ReqMsgConvertMeetingId::setMailbox( const QString& aMailbox )
+{
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgConvertMeetingId::setMailbox" );
+#endif 
+       int err = setNodeValue( QString( "Mailbox" ), aMailbox, QDomNode::AttributeNode, QString( "AlternateId" ) );
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgConvertMeetingId::setMailbox end : err=%d", err );
+#endif
+       return err;
+}
+
+/*
+ * ReqMsgGetCalendarItem class functions
+ */
+ReqMsgGetCalendarItem::ReqMsgGetCalendarItem( const QString& aItemId ) : RequestMessage( ReqCmdGetItem )
+{
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetCalendarItem::ReqMsgGetCalendarItem" );
+#endif 
+       if( iMessage && iCurrCmd == ReqCmdGetItem )
+       {
+               setNodeValue( QString( "BaseShape" ), QString( "AllProperties" ) );
+               
+               if( aItemId != QString::null )
+                       setItemId( aItemId );
+       }
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetCalendarItem::ReqMsgGetCalendarItem end" );
+#endif
+}
+
+int ReqMsgGetCalendarItem::setItemId( const QString& aItemId )
+{
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetCalendarItem::setItemId" );
+#endif 
+       int err = setNodeValue( QString( "Id" ), aItemId, QDomNode::AttributeNode, QString( "ItemId" ), 0 );
+#ifdef MU_DEBUG
+       qDebug( "ReqMsgGetCalendarItem::setItemId end : err=%d", err );
+#endif 
+       return err;
+}
+
+/*
+ * ResMsgGetUserAvailability class functions
+ */
+ResMsgGetUserAvailability::ResMsgGetUserAvailability( const QByteArray& aData ) : ResponseMessage( aData )
+{
+#ifdef MU_DEBUG
+       qDebug( "ResMsgGetUserAvailability::ResMsgGetUserAvailability" );
+       qDebug( "ResMsgGetUserAvailability::ResMsgGetUserAvailability end" );
+#endif
+}
+
+int ResMsgGetUserAvailability::getMeetingsFromResponse( QList<Meeting*>& aMeetings, const Room &aRoom )
+{
+#ifdef MU_DEBUG
+       qDebug( "ResMsgGetUserAvailability::getMeetingsFromResponse" );
+#endif
+               if( !iMessage )
+                       {
+#ifdef MU_DEBUG
+       qDebug( "ResMsgGetUserAvailability::getMeetingsFromResponse : iMessage is NULL" );
+#endif 
+                       return MsgErrSomeError;
+                       }
+
+               //TODO: Clean this function a bit (see getMeetingDetailsFromResponse)
+               
+               int err = MsgErrNoError;
+
+               QDomNodeList list = iMessage->elementsByTagName( QString( "CalendarEvent" ) );
+
+               for( int i=0; i<list.count(); i++ )
+               {
+                       QDomElement e = list.item( i ).toElement();
+                       QString tagName = ( e.prefix() == QString::null ) ? e.tagName().toLower() : e.localName().toLower();
+
+                       if( !e.isNull() && tagName == "calendarevent" )
+                       {
+
+                               QString id, startsAt, endsAt, organizer, subject;
+
+                               for ( QDomNode subnode = e.firstChild(); !subnode.isNull(); subnode = subnode.nextSibling() )
+                               {
+                                       QDomElement e = subnode.toElement();
+                                       QString tagName = ( e.prefix() == QString::null ) ? e.tagName().toLower() : e.localName().toLower();
+
+                                       if( tagName == QString( "starttime" ) )
+                                       {
+                                               startsAt = e.text();
+                                       }
+                                       else if( tagName == QString( "endtime" ) )
+                                       {
+                                               endsAt = e.text();
+                                       }
+                                       else if( tagName == QString( "calendareventdetails" ) )
+                                       {
+
+                                               for ( QDomNode detailnode = subnode.firstChild(); !detailnode.isNull(); detailnode = detailnode.nextSibling() )
+                                               {
+
+                                                       QDomElement e = detailnode.toElement();
+                                                       QString tagName = ( e.prefix() == QString::null ) ? e.tagName().toLower() : e.localName().toLower();
+
+                                                       if( tagName == QString( "id" ) )
+                                                       {                                                       
+                                                               id = e.text();
+                                                       }
+
+                                                       if( tagName == QString( "subject" ) )
+                                                       {
+                                                               subject = e.text();
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               QDateTime start = QDateTime::fromString( startsAt, Qt::ISODate );
+                               QDateTime end = QDateTime::fromString( endsAt, Qt::ISODate );
+
+                               aMeetings.append( new Meeting(
+                                               id,
+                                               aRoom,
+                                               start,
+                                               end,
+                                               subject ) );
+
+                       }
+               }
+#ifdef MU_DEBUG
+       qDebug( "ResMsgGetUserAvailability::getMeetingsFromResponse end : err=%d", err );
+#endif         
+               return err;
+}
+
+/*
+ * ResMsgGetCalendarItem class functions
+ */
+int ResMsgGetCalendarItem::getMeetingDetailsFromResponse( Meeting& aMeeting )
+{
+#ifdef MU_DEBUG
+       qDebug( "ResMsgGetCalendarItem::getMeetingDetailsFromResponse" );
+#endif
+       if( !iMessage || hasErrors() )
+               {
+#ifdef MU_DEBUG
+       qDebug( "ResMsgGetCalendarItem::getMeetingDetailsFromResponse : iMessage is NULL or response has errors." );
+#endif         
+               return MsgErrSomeError;
+               }
+
+       QString name, address, description; //Organizer
+
+       QDomNode box = getElementFromDocument( QString( "Mailbox" ), QString( "Organizer" ), 0 );
+
+       if( !box.isNull() && box.hasChildNodes() )
+       {
+               for ( QDomNode subnode = box.firstChild(); !subnode.isNull(); subnode = subnode.nextSibling() )
+               {
+                       if( matchName( subnode, QString( "Name" ) ) )
+                               name = subnode.toElement().text();
+                       else if( matchName( subnode, QString( "EmailAddress" ) ) )
+                               address = subnode.toElement().text();
+               }
+       }
+       
+       QDomNode body = getElementFromDocument( QString( "Body" ), QString( "CalendarItem" ), 0 );
+
+       if( body.isElement() )
+               description = body.toElement().text();
+       
+       aMeeting.setOrganizer( name, address );
+       aMeeting.setDescription( description );
+
+#ifdef MU_DEBUG
+       qDebug( "ResMsgGetCalendarItem::getMeetingDetailsFromResponse end" );
+#endif         
+       return MsgErrNoError;
+}
+
diff --git a/src/IO/Communication/MessagingUtils.h b/src/IO/Communication/MessagingUtils.h
new file mode 100644 (file)
index 0000000..b15a99b
--- /dev/null
@@ -0,0 +1,611 @@
+#ifndef MESSAGINGUTILS_H_
+#define MESSAGINGUTILS_H_
+
+#include <QObject>
+#include <QDomDocument>
+#include <QDateTime>
+#include <QStringList>
+
+//Namespace definitions
+#define NS_XSI "http://www.w3.org/2001/XMLSchema-instance"
+#define NS_XSD "http://www.w3.org/2001/XMLSchema"
+#define NS_SOAP "http://schemas.xmlsoap.org/soap/envelope/"
+#define NS_T "http://schemas.microsoft.com/exchange/services/2006/types"
+#define NS_MSG "http://schemas.microsoft.com/exchange/services/2006/messages"
+
+//Used for http request header to define web service operation
+#define ACTION_URL "http://schemas.microsoft.com/exchange/services/2006/messages/"
+
+//Set MessagingUtils Debug on/off
+//#define MU_DEBUG
+#undef MU_DEBUG
+
+class Meeting;
+class Room;
+
+//All supported operations for web services
+//Operations are described here: http://msdn.microsoft.com/en-us/library/bb409286.aspx
+enum RequestCommandId
+{
+       ReqCmdNoCommand = 0,
+       ReqCmdAddDelegate, //1
+       ReqCmdConvertId, //2 Used for converting fetched IDs to match the format in GetItem request
+       ReqCmdCopyFolder, //3
+       ReqCmdCopyItem, //4
+       ReqCmdCreateAttachment, //5
+       ReqCmdCreateFolder, //6
+       ReqCmdCreateItem, //7
+       ReqCmdCreateManagedFolder, //8
+       ReqCmdDeleteAttachment, //9
+       ReqCmdDeleteFolder, //10
+       ReqCmdDeleteItem, //11
+       ReqCmdExpandDL, //12
+       ReqCmdFindFolder, //13
+       ReqCmdFindItem, //14
+       ReqCmdGetAttachment, //15
+       ReqCmdGetDelegate, //16
+       ReqCmdGetEvents, //17
+       ReqCmdGetFolder, //18
+       ReqCmdGetItem, //19 Used for getting the detailed information about some item (calendar event)
+       ReqCmdGetUserAvailability, //20 Used for fetching meetings
+       ReqCmdGetUserOofSettings, //21
+       ReqCmdMoveFolder, //22
+       ReqCmdMoveItem, //23
+       ReqCmdRemoveDelegate, //24
+       ReqCmdResolveNames, //25
+       ReqCmdSendItem, //26
+       ReqCmdSetUserOofSettings, //27
+       ReqCmdSubscribe, //28
+       ReqCmdSyncFolderHierarchy, //29
+       ReqCmdSyncFolderItems, //30
+       ReqCmdUnsubscribe, //31
+       ReqCmdUpdateDelegate, //32
+       ReqCmdUpdateFolder, //33
+       ReqCmdUpdateItem //34
+};
+
+//TODO: Define more specific errors
+enum MessagingError
+{
+       MsgErrNoError = 0,
+       MsgErrSomeError
+};
+
+//! Struct to present a node in SOAP envelope message.
+/*!
+ *     Struct to present a node in SOAP envelope message.
+ *  Request messages are formed by using predefined arrays
+ *  of MessageBodyElement objects.
+ */
+typedef struct MessageBodyElement
+{
+       //! Depth of the node in document tree. For example, root node should be 0.
+       int iTraversalLevel;
+       //! Namespace of the node. QString::null if not specified.
+       QString iNamespace;
+       //! Name of the node.
+       QString iElementName;
+       //! Type of the node. Currently QDomNode::ElementNode and QDomNode::AttributeNode are supported.
+       QDomNode::NodeType iNodeType;
+};
+
+//SOAP Envelope templates for web service operations
+//Operations are described here: http://msdn.microsoft.com/en-us/library/bb409286.aspx
+/*
+ * NOTES: 
+ * - First node's TraversalLevel must always be 0.
+ * - Namespace can be defined as an URI or QString::null
+ * - NodeType can be QDomNode::ElementNode or QDomNode::AttributeNode
+ * - Nodes must be defined in descending order, according to schema.
+ * - Attribute must be defined right after it's owner element and it's traversal level must be same.
+ */
+const MessageBodyElement reqCmdArrayEnvelopeBase[] =
+{
+               { 0, NS_SOAP, "Envelope", QDomNode::ElementNode }/*,
+               { 0, "xmlns", "xsi", QDomNode::AttributeNode },
+               { 0, "xmlns", "xsd", QDomNode::AttributeNode },
+               { 0, "xmlns", "soap", QDomNode::AttributeNode },
+               { 0, "xmlns", "t", QDomNode::AttributeNode },*/
+};
+
+const MessageBodyElement reqCmdMailboxElement[] =
+{
+               { 0, NS_T, "MailboxData", QDomNode::ElementNode },
+               { 1, NS_T, "Email", QDomNode::ElementNode },
+               { 2, NS_T, "Address", QDomNode::ElementNode },
+               { 1, NS_T, "AttendeeType", QDomNode::ElementNode },
+               { 1, NS_T, "ExcludeConflicts", QDomNode::ElementNode },
+};
+
+const MessageBodyElement reqCmdArrayGetUserAvailability[] =
+{
+               { 0, NS_SOAP, "Body", QDomNode::ElementNode },
+               { 1, NS_MSG, "GetUserAvailabilityRequest", QDomNode::ElementNode },
+               { 2, NS_T, "TimeZone", QDomNode::ElementNode },
+               { 3, QString::null, "Bias", QDomNode::ElementNode },
+               { 3, QString::null, "StandardTime", QDomNode::ElementNode },
+               { 4, QString::null, "Bias", QDomNode::ElementNode },
+               { 4, QString::null, "Time", QDomNode::ElementNode },
+               { 4, QString::null, "DayOrder", QDomNode::ElementNode },
+               { 4, QString::null, "Month", QDomNode::ElementNode },
+               { 4, QString::null, "DayOfWeek", QDomNode::ElementNode },
+               //</standardtime>
+               { 3, QString::null, "DaylightTime", QDomNode::ElementNode },
+               { 4, QString::null, "Bias", QDomNode::ElementNode },
+               { 4, QString::null, "Time", QDomNode::ElementNode },
+               { 4, QString::null, "DayOrder", QDomNode::ElementNode },
+               { 4, QString::null, "Month", QDomNode::ElementNode },
+               { 4, QString::null, "DayOfWeek", QDomNode::ElementNode },
+               //</daylighttime>
+               //</timezone>
+               //Use meetingroom addresses to fetch meetings for rooms. Mailboxdata-element for each.
+               { 2, QString::null, "MailboxDataArray", QDomNode::ElementNode },
+
+               //MAILBOX DATA(s) MUST BE ADDED AFTERWARDS
+               //SEE: reqCmdMailboxElement[]
+
+               //</mailboxdeataarray>
+               { 2, NS_T, "FreeBusyViewOptions", QDomNode::ElementNode },
+               //Use Timewindow to define from which period we want to fetch meetings
+               { 3, NS_T, "TimeWindow", QDomNode::ElementNode },
+               { 4, NS_T, "StartTime", QDomNode::ElementNode },
+               { 4, NS_T, "EndTime", QDomNode::ElementNode },
+               //</timewindow>
+               { 3, NS_T, "MergedFreeBusyIntervalInMinutes", QDomNode::ElementNode },
+               { 3, NS_T, "RequestedView", QDomNode::ElementNode },
+               //</freebusyviewoptions>
+               //</getuseravailabilityrequest>
+};
+
+const MessageBodyElement reqCmdArrayGetCalendarItem[] =
+{
+               { 0, NS_SOAP, "Body", QDomNode::ElementNode },
+               { 1, NS_MSG, "GetItem", QDomNode::ElementNode },
+               //{ 1, QString::null, "xmlns", QDomNode::AttributeNode },
+               { 2, QString::null, "ItemShape", QDomNode::ElementNode },
+               { 3, NS_T, "BaseShape", QDomNode::ElementNode },
+               { 2, QString::null, "ItemIds", QDomNode::ElementNode },
+               { 3, NS_T, "ItemId", QDomNode::ElementNode },
+               { 3, QString::null, "Id", QDomNode::AttributeNode }
+};
+
+const MessageBodyElement reqCmdArrayConvertIdHeader[] =
+{
+               { 0, NS_SOAP, "Header", QDomNode::ElementNode },
+               { 1, NS_T, "RequestServerVersion", QDomNode::ElementNode },
+               { 1, QString::null, "Version", QDomNode::AttributeNode },
+
+};
+
+const MessageBodyElement reqCmdArrayConvertId[] =
+{
+               { 0, NS_SOAP, "Body", QDomNode::ElementNode },
+               { 1, NS_MSG, "ConvertId", QDomNode::ElementNode },
+               //{ 1, QString::null, "xmlns:t", QDomNode::AttributeNode },
+               //{ 2, "xmlns", "t", QDomNode::AttributeNode },
+               { 1, QString::null, "DestinationFormat", QDomNode::AttributeNode },
+               { 2, QString::null, "SourceIds", QDomNode::ElementNode },
+               { 3, NS_T, "AlternateId", QDomNode::ElementNode },
+               { 3, QString::null, "Format", QDomNode::AttributeNode },
+               { 3, QString::null, "Id", QDomNode::AttributeNode },
+               { 3, QString::null, "Mailbox", QDomNode::AttributeNode },
+};
+
+
+//! Base class for Request and Response message classes
+/*!
+ *  This class provides basic functionality to use generated SOAP envelope DomDocument object.
+ */
+class BaseMessage : public QObject
+{
+       Q_OBJECT
+
+public:
+
+       //! Constructor.
+       BaseMessage();
+       //! Destructor.
+       virtual ~BaseMessage();
+
+       //! Current generated SOAP envelope DomDocument object as byte array.
+       /*!
+        *      Returns current message envelope as byte array.
+        *  This array is used to provide a content for http request.
+        * \return current message envelope as byte array.
+        */ 
+       QByteArray getMessage();
+
+protected:
+
+       //! List of QDomNode objects matching desired criteria.
+       /*!
+        *  Returns a list of nodes that matches the given aNodeName.
+        *  Optional parameters can be provided to narrow the search.
+        * \param aNodeName Name of the node(s).
+        * \param aParentName Name of the parent node. Optional. 
+        *  If not specified, base node of the QDomDocument is used.
+        * \param aRootNode Root node for the search. Optional.
+        *  If provided, only it's childnodes will be searched.
+        *  If not specified, base node of the QDomDocument is used.
+        * \return List of QDomNodes matching the criteria.
+        */
+       QList<QDomNode> getNodesByName( const QString& aNodeName,
+                                                                       const QString& aParentName = QString::null,
+                                                                       QDomNode* aRootNode = NULL );
+
+       //! Single node matching desired criteria.
+       /*!
+        *  Returns a single node that matches the given aNodeName.
+        *  Optional parameters can be provided to narrow the search.
+        * \param aNodeName Name of the node.
+        * \param aNodeType Type of the node. Currently QDomNode::ElementNode and QDomNode::AttributeNode are supported.
+        * \param aParentName Name of the parent node. Optional. 
+        *  If not specified, base node of the QDomDocument is used.
+        * \param aIndex If multiple results are found, an index of desired node can be used. Optional.
+        * \param aRootNode Root node for the search. Optional.
+        *  If provided, only it's childnodes will be searched.
+        *  If not specified, base node of the QDomDocument is used.
+        * \return QDomNode matching the criteria.
+        */
+       QDomNode getNodeFromDocument( const QString& aNodeName,
+                                                                       QDomNode::NodeType aNodeType,
+                                                                       const QString& aParentName = QString::null,
+                                                                       int aIndex = 0,
+                                                                       QDomNode* aRootNode = NULL );
+
+       //! Single element matching desired criteria.
+       /*!
+        *  See getNodeFromDocument for details.
+        */
+       QDomNode getElementFromDocument( const QString& aElementName,
+                                                                       const QString& aParentName = QString::null,
+                                                                       int aIndex = 0,
+                                                                       QDomNode* aRootNode = NULL );
+       
+       //! Single attribute matching desired criteria.
+       /*!
+        *  See getNodeFromDocument for details.
+        */
+       QDomNode getAttributeFromDocument( const QString& aAttributeName,
+                                                                       const QString& aParentName = QString::null,
+                                                                       int aIndex = 0,
+                                                                       QDomNode* aRootNode = NULL );
+
+       //! Compare node name to string.
+       /*!
+        *      Checks if name of the provided node matches aName.
+        *  Node can be QDomNode::ElementNode or QDomNode::AttributeNode.
+        * \param aNode Node to compare.
+        * \param aName Name to compare.
+        * \return True if comparison matches. Otherwise false.
+        *  NOTE: This function does comparison for node's local name, so it ignores possible prefixes in a tag name.
+        */
+       bool matchName( const QDomNode& aNode, const QString& aName  );
+
+
+
+protected:
+
+       /*!
+        * Current generated SOAP envelope DomDocument object.
+        */
+       QDomDocument* iMessage;
+
+};
+
+//! Base class for Requests
+/*!
+ *  This class provides basic functionality to use generated SOAP envelope DomDocument object for http requests.
+ */
+class RequestMessage : public BaseMessage
+{
+
+public:
+
+       //! Constructor
+       /*!
+        * \param aCommandId Id to identify operation type.
+        */
+       RequestMessage( RequestCommandId aCommandId = ReqCmdNoCommand );
+       RequestMessage( const QString& aFileName );
+       //! Destructor
+       virtual ~RequestMessage(){};
+
+public:
+
+       //! Add node to message
+       /*!
+        *  Adds node to a request message. Parameters can be provided to specify location.
+        * \param aNode Node to add.
+        * \param aNodeType Type of node. QDomNode::ElementNode and QDomNode::AttributeNode are supported. Default is QDomNode::ElementNode.
+        * \param aParentName Name of the parent. Optional. If provided, node will be added as it's child. Otherwise root of the QDomDocument is used.
+        * \param aIndex Index to add. Optional. If multiple parents are found, index to add can be specified.
+        * \param aRootNode Root node to search. Optional. Searches only it's child nodes for a parent if provided. Otherwise root of the QDomDocument is used.
+        * \return An error code.
+        */
+       int addNode( const QDomNode& aNode,
+                                       QDomNode::NodeType aNodeType = QDomNode::ElementNode,
+                                       const QString& aParentName = QString::null,
+                                       int aIndex = 0,
+                                       QDomNode* aRootNode = NULL );
+
+       //! Set value of the node
+       /*!
+        *  Sets the value of specified node. Parameters can be used to narrow the search.
+        * \param aNodeName Name of the node.
+        * \param aValue Value to set.
+        * \param aNodeType Type of node. QDomNode::ElementNode and QDomNode::AttributeNode are supported. Default is QDomNode::ElementNode.
+        * \param aParentName Name of the parent node. Optional. 
+        *  If not specified, base node of the QDomDocument is used.
+        * \param aIndex If multiple results are found, an index of desired node can be used. Optional.
+        * \param aRootNode Root node for the search. Optional.
+        *  If provided, only it's childnodes will be searched.
+        *  If not specified, base node of the QDomDocument is used.
+        * \return An error code.
+        */
+       int setNodeValue( const QString& aNodeName,
+                                               const QString& aValue,
+                                               QDomNode::NodeType aNodeType = QDomNode::ElementNode,
+                                               const QString& aParentName = QString::null,
+                                               int aIndex = 0,
+                                               QDomNode* aRootNode = NULL );
+
+       //! Create the structure of message (soap:Body)
+       /*
+        * \return An error code.
+        */
+       int createMessageStructure();
+       //! Create the structure of message (soap:Body)
+       /*
+        * \param aCommandId Id of command. Structure is constructed according to this.
+        * \return An error code.
+        */
+       int createMessageStructure( RequestCommandId aCommandId );
+       
+       //! Create the base of the request envelope (soap:Envelope)
+       /*!
+        * \return An error code.
+        */
+       int createEnvelopeBase();
+
+       //! Get operation specific content type string for http request header.
+       /*!
+        * \param aCommandId Id of the command (operation)
+        * \return Content type string for header
+        */
+       QString getContentTypeForHeader( RequestCommandId aCommandId = ReqCmdNoCommand );
+
+protected:
+
+       //! Construct an array of MessageBodyElements to a node.
+       /*!
+        *  Constructs an array of predefined MessageBodyElements to node.
+        *  This function is used to form different parts of message from MessageBodyElements to QDomNodes
+        * \param aArray Array of MessageBodyElements.
+        * \param aSize Size of an array.
+        * \return Created node.
+        */
+       QDomNode constructArrayToNode( const MessageBodyElement* aArray, int aSize );
+       
+protected:
+
+       //! Id of current operation
+       RequestCommandId iCurrCmd;
+};
+
+//! Base class for Responses.
+/*!
+ *  This class provides basic functionality to use generated SOAP envelope DomDocument object from http responses.
+ */
+class ResponseMessage : public BaseMessage
+{
+
+public:
+
+       //! Constructor
+       ResponseMessage();
+
+       //! Constructor
+       /*!
+        * \param aData Byte array to construct ResponseMessage from.
+        */
+       ResponseMessage( const QByteArray& aData );
+
+       //! Destructor
+       virtual ~ResponseMessage(){};
+
+       //! Get the value of node.
+       /*!
+        *  Gets a value of single node. Optional parameters are used to define desired node in more detail.
+        * \param aNodeName Name of the node.
+        * \param aNodeType Type of the node. QDomNode::ElementNode and QDomNode::AttributeNode are supported.
+        * \param aParentname Name of the parent node. Optional. Can be specified to narrow the search.
+        * \param aIndex Index of the node. Optional. If multiple results are found, index can be defined to specify the result.
+        * \param aRootNode Root node. Optional. If specified, only it's children are included in search. Otherwise, root node of QDomDocument is used.
+        * \return Value of the node.
+        */
+       QString getNodeValue( const QString& aNodeName,
+                                                       QDomNode::NodeType aNodeType,
+                                                       const QString& aParentName = QString::null,
+                                                       int aIndex = 0,
+                                                       QDomNode* aRootNode = NULL );
+
+       //! Checks if there are any errors in response.
+       /*!
+        *  If any value of status elements in response message is not success, this function
+        *  returns true.
+        * \return True if errors exist. Otherwise false.
+        */
+       bool hasErrors();
+
+protected:
+
+};
+
+
+//Operation specific inherited classes
+
+
+//! Request message for GetUserAvailability operation.
+class ReqMsgGetUserAvailability : public RequestMessage
+{
+
+       enum UserAttendeeType
+       {
+               AttendeeOrganizer = 0,
+               AttendeeRequired,
+               AttendeeOptional,
+               AttendeeRoom,
+               AttendeeResource
+       };
+
+public:
+
+       //! Constructor
+       ReqMsgGetUserAvailability();
+       //! Destructor
+       virtual ~ReqMsgGetUserAvailability(){};
+       //! Set the current time zone.
+       /*
+        * \return An error code.
+        */
+       int setTimeZone(); //TODO: initializable with parameters?
+       
+       //! Add user (mailbox) to search availability status from.
+       /*
+        * Add user (mailbox) to search calendar events from. 
+        * Multiple users can be added in one request.
+        * \param aAddress User's EMail address.
+        * \param aAttendeeType Type of the attendance. Default is "Required".
+        * \param aExcludeConflicts Exclude conflicting meetings. Default is "false".
+        * \return An error code.
+        */
+       int addUser( const QString& aAddress, const QString& aAttendeeType = "Required", const QString& aExcludeConflicts = "false" ); //TODO: Is resource a correct type for room?
+       
+       //! Set the time window for request.
+       /*!
+        * Set the time window to search availability statuses from.
+        * \param aStart Start date time.
+        * \param aEnd End date time.
+        * \return An error code.
+        * NOTE: Server might give an error if too wide time window is specified.
+        * ~3 weeks should be safe.
+        */
+       int setTimeWindow( const QDateTime& aStart, const QDateTime& aEnd );
+
+private:
+
+};
+
+//! Request message for ConvertId operation.
+/*!
+ * This is used to convert HexEntryId type unique Id's of calendar events
+ * To EwsLegacyId type. Latter type of Id must be provided in order to get detailed information for calendar event.
+ */
+class ReqMsgConvertMeetingId : public RequestMessage
+{
+public:
+       //! Constructor
+       /*!
+        * \param aItemId HexEntryId type Id to convert. Optional (though must be set later).
+        * \param aMailBox EMail address of calendar event's owner.
+        */
+       ReqMsgConvertMeetingId( const QString& aItemId = QString::null, const QString& aMailbox = QString::null );
+       
+       //! Destructor
+       virtual ~ReqMsgConvertMeetingId(){};
+       
+       //! Set item id.
+       /*
+        * \param aItemId Id of calendar event in HexEntryId format
+        * \return An error code.
+        */
+       int setItemId( const QString& aItemId );
+       
+       //! Set Mailbox.
+       /*!
+        *  Set the calendar event owner's mailbox EMail address.
+        * \param aMailBox Mailbox address.
+        * \return An error code.
+        */
+       int setMailbox( const QString& aMailbox );
+       
+private:
+       
+};
+
+//! Request message for GetItem (Calendar) operation.
+/*!
+ *  This is used to get more detailed information about calendar event.
+ */
+class ReqMsgGetCalendarItem : public RequestMessage
+{
+public:
+
+       //! Constructor
+       /*!
+        * \param aItemId secondary Id ( EwsLegacyId type obtained from ConvertId operation ) of calendar event.
+        */
+       ReqMsgGetCalendarItem( const QString& aItemId = QString::null );
+       
+       //! Destructor
+       virtual ~ReqMsgGetCalendarItem(){};
+       
+       //! Set the Id of calendar event.
+       /*!
+        * This must be EwsLegacyId type obtained from ConvertId operation.
+        * \param aItemId Id of item.
+        * \return An error code.
+        */
+       int setItemId( const QString& aItemId );        
+       //int setChangeKey( const QString& aChangeKey ){};
+       
+private:
+
+};
+
+//! Response message for GetUserAvailability operation.
+class ResMsgGetUserAvailability : public ResponseMessage
+{
+public:
+
+       //! Constructor
+       /*!
+        * \param aData Byte array to construct response message from.
+        */
+       ResMsgGetUserAvailability( const QByteArray& aData );
+       
+       //! Destructor
+       virtual ~ResMsgGetUserAvailability(){};
+       //! Get Meetings from constructed response.
+       /*!
+        * \param aList List of Meeting objects to fill.
+        * \param aRoom Room for Meeting objects.
+        * \return An error code.
+        */
+       int getMeetingsFromResponse( QList<Meeting*>& aList, const Room &aRoom );
+};
+
+//! Response message for GetItem (Calendar) operation.
+class ResMsgGetCalendarItem : public ResponseMessage
+{
+public:
+       //! Constructor
+       /*!
+        * \param aData Byte array to construct response message from.
+        */
+       ResMsgGetCalendarItem( const QByteArray& aData ) : ResponseMessage( aData ){};
+       
+       //! Destructor
+       virtual ~ResMsgGetCalendarItem(){};
+       
+       //! Get meeting details from constructed response.
+       /*!
+        * \param aMeeting Meeting to get details for.
+        * \return An error code.
+       */
+       int getMeetingDetailsFromResponse( Meeting& aMeeting );
+
+};
+
+#endif /*MESSAGINGUTILS_H_*/
diff --git a/src/IO/DeviceControl/AlarmSender.cpp b/src/IO/DeviceControl/AlarmSender.cpp
new file mode 100644 (file)
index 0000000..b49742b
--- /dev/null
@@ -0,0 +1,200 @@
+#include "AlarmSender.h"
+#include "DeviceConstants.h"
+
+#include <QtDebug>
+#include <QFile>
+
+AlarmSender::AlarmSender( DeviceDataStorage *aDataStorage )
+{
+       qDebug() << "AlarmSender( DeviceDataStorage * )";
+       iDataStorage = aDataStorage;
+}
+
+AlarmSender::~AlarmSender()
+{
+       qDebug() << "~AlarmSender()";
+}
+
+bool AlarmSender::sendAlarms( QTime aTurnOnAt, QTime aTurnOffAt, int aDays )
+{
+       qDebug() << "AlarmSender::sendAlarms( QTime, QTime, int )";
+       QString errortext;
+
+       if ( aDays != 5 ) //if aDays is 5 we set the alarms only for working days
+               aDays = 7;
+
+       if ( !removeStoredAlarms() ) //remove possible old alarms
+               return false;
+
+       alarm_event_t eventOn;
+       alarm_event_t eventOff;
+
+       //zero the alarm events
+       memset( &eventOn, 0, sizeof( alarm_event_t ) );
+       memset( &eventOff, 0, sizeof( alarm_event_t ) );
+
+       //set the common event fields for the alarm events
+       eventOn.recurrence = 60 * 24 * 7; //minutes in a week
+       eventOff.recurrence = 60 * 24 * 7; //minutes in a week
+       eventOn.recurrence_count = -1;
+       eventOff.recurrence_count = -1;
+       eventOn.flags = ( ALARM_EVENT_BOOT | ALARM_EVENT_NO_DIALOG );
+       eventOff.flags = ALARM_EVENT_NO_DIALOG;
+       eventOff.exec_name = ( QString( BinPath + DevStopper ).toLatin1() ).data();;
+
+       //find the first possible points of time to set the first alarms
+       // Adjust the time. NOTE: alarms cannot be set to past
+       QDateTime turnOnAtBasis = findFirstTime( aDays, aTurnOnAt );
+       QDateTime turnOffAtBasis = findFirstTime( aDays, aTurnOffAt );
+
+       cookie_t cookie;
+       int index = 0;
+
+       while ( index++ < aDays )
+       {
+
+               //send auto switch on alarms
+               eventOn.alarm_time = turnOnAtBasis.toTime_t();
+               cookie = alarm_event_add( &eventOn );
+               if ( !handleCookie( cookie, errortext ) )
+               {
+                       emit alarmSendingFailed( DeviceManager::NewAlarmsNotSent, errortext );
+                       removeAlarms();
+                       return false;
+               }
+               turnOnAtBasis = turnOnAtBasis.addDays( 1 ); //move on to next day
+               if ( aDays == 5 ) //only for working days
+                       turnOnAtBasis = turnOnAtBasis.addDays( daysToNextWorkingDay( turnOnAtBasis ) );
+
+               //send auto switch off alarms
+               eventOff.alarm_time = turnOffAtBasis.toTime_t();
+               cookie = alarm_event_add( &eventOff );
+               if ( !handleCookie( cookie, errortext ) )
+               {
+                       emit alarmSendingFailed( DeviceManager::NewAlarmsNotSent, errortext );
+                       removeAlarms();
+                       return false;
+               }
+               turnOffAtBasis = turnOffAtBasis.addDays( 1 ); //move on to next day
+               if ( aDays == 5 ) //only for working days
+                       turnOffAtBasis = turnOffAtBasis.addDays( daysToNextWorkingDay( turnOffAtBasis ) );
+       }
+       if ( !iDataStorage->storeData( iDataStorage->dataSectionToString( DeviceDataStorage::Alarms ), iSentAlarms ) )
+       {
+               emit alarmSendingFailed( DeviceManager::NewAlarmsNotStored, errortext );
+               removeAlarms();
+               return false;
+       }
+       return true;
+}
+
+bool AlarmSender::removeStoredAlarms()
+{
+       qDebug() << "AlarmSender::removeStoredAlarms()";
+       QStringList storedAlarms;
+       QString errortext;
+       if ( !iDataStorage->readData( iDataStorage->dataSectionToString( DeviceDataStorage::Alarms ), storedAlarms ) )
+       {
+               emit alarmSendingFailed( DeviceManager::OldAlarmsNotRemoved, errortext );
+               return false;
+       }
+
+       for ( int i = 0; i < storedAlarms.size(); ++i )
+               alarm_event_del( storedAlarms.at( i ).toLong() );
+       
+       // clearing the removed alarms from the storage by saving an empty alarm list
+       storedAlarms.clear();
+       iDataStorage->storeData( iDataStorage->dataSectionToString( DeviceDataStorage::Alarms ), storedAlarms );
+       // catching an error in this case is not needed
+
+       return true;
+}
+
+void AlarmSender::removeAlarms()
+{
+       qDebug() << "AlarmSender::removeAlarms()";
+       for ( int i = 0; i < iSentAlarms.size(); ++i )
+               alarm_event_del( iSentAlarms.at( i ).toLong() );
+
+       // clearing the removed alarms from the storage by saving an empty alarm list
+       iSentAlarms.clear();
+       iDataStorage->storeData( iDataStorage->dataSectionToString( DeviceDataStorage::Alarms ), iSentAlarms );
+       // catching an error in this case is not needed
+}
+
+QDateTime AlarmSender::findFirstTime( const int &aDays, const QTime &aTime )
+{
+       qDebug() << "AlarmSender::findFirstTime( const int &, const QTime & )";
+       QDateTime currentTime = QDateTime::currentDateTime();
+       QDateTime dateTimeBasis = QDateTime::currentDateTime();
+       dateTimeBasis = dateTimeBasis.addSecs( dateTimeBasis.time().secsTo( aTime ) );
+
+       if ( currentTime > dateTimeBasis )   //have to add a day
+       {
+               dateTimeBasis = dateTimeBasis.addDays( 1 );
+       }
+       if ( aDays == 5 )   //only for working days
+       {
+               dateTimeBasis = dateTimeBasis.addDays( daysToNextWorkingDay( dateTimeBasis ) );
+       }
+       return dateTimeBasis;
+}
+
+int AlarmSender::daysToNextWorkingDay( const QDateTime &aDateTime )
+{
+       qDebug() << "AlarmSender::daysToNextWorkingDay( const QDateTime & )";
+       QString day = aDateTime.toString( "ddd" );
+       if ( day == "Sat" )
+               return 2;
+       else if ( day == "Sun" )
+               return 1;
+       else
+               return 0;
+}
+
+bool AlarmSender::handleCookie( cookie_t aCookie, QString &aErrorText )
+{
+       qDebug() << "AlarmSender::handleCookie( cookie_t, QStringList &, QString & )";
+       if ( aCookie == 0 )
+       {
+               aErrorText = mapError( alarmd_get_error() );
+               return false;
+       }
+       else
+       {
+               QString cookieStr;
+               cookieStr.append( QString( "%1" ).arg( aCookie ) );
+               iSentAlarms.append( cookieStr );
+       }
+       return true;
+}
+
+QString AlarmSender::mapError( alarm_error_t aErrorCode )
+{
+       qDebug() << "AlarmSender::mapError( alarm_error_t )";
+       QString errorMessage;
+       switch ( aErrorCode )
+       {
+               case ALARMD_SUCCESS:
+                       errorMessage = "No reason found."; //this should never happen
+                       break;
+               case ALARMD_ERROR_DBUS:
+                       errorMessage = "An error with D-Bus occurred, probably coudn't get a D-Bus connection.";
+                       break;
+               case ALARMD_ERROR_CONNECTION:
+                       errorMessage = "Could not contact alarmd via D-Bus.";
+                       break;
+               case ALARMD_ERROR_INTERNAL:
+                       errorMessage = "Some alarmd or libalarm internal error, possibly a version mismatch.";
+                       break;
+               case ALARMD_ERROR_MEMORY:
+                       errorMessage = "A memory allocation failed.";
+                       break;
+               case ALARMD_ERROR_ARGUMENT:
+                       errorMessage = "An argument given by caller was invalid.";
+                       break;
+               default: /* == 6 */
+                       errorMessage = "Alarm daemon not running.";
+       }
+       return errorMessage;
+}
diff --git a/src/IO/DeviceControl/AlarmSender.h b/src/IO/DeviceControl/AlarmSender.h
new file mode 100644 (file)
index 0000000..9920378
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef ALARMSENDER_H_
+#define ALARMSENDER_H_
+
+extern "C"
+{
+#include <alarmd/alarm_event.h>
+}
+#include "DeviceDataStorage.h"
+
+#include <QObject>
+#include <QTime>
+
+//! DeviceControl class. Sends and removes the alarms of the alarm daemon.
+/*!
+ * DeviceControl class. Sends and removes the alarms of the alarm daemon. The alarms make it possible
+ * to rurn on and off the device in the desired points of time. This optional functionality is supported
+ * in the "kiosk mode".
+ */
+class AlarmSender : public QObject
+{
+       Q_OBJECT
+
+public:
+       //! Constructor.
+       /*!
+        * Constructor to initialize an AlarmSender instance
+        * \param aDataStorage Pointer to the DataStorage class instance.
+        */
+       AlarmSender( DeviceDataStorage *aDataStorage );
+       //! Destructor.
+       virtual ~AlarmSender();
+
+signals:
+       //! Signal. Emitted if error occured during sending the alarms.
+       /*!
+        * Signal. Emitted if error occured during sending the alarms.
+        * \param aErrorCode The error code.
+        * \param aAddInfo The additional error text.
+        */
+       void alarmSendingFailed( DeviceManager::ErrorCode aErrorCode, const QString &aAddInfo );
+
+public slots:
+       //! Slot. Consists and sends the alarms to the alarm daemon.
+       /*!
+        * Slot. Consists and sends the alarms to the alarm daemon. Asks DeviceDataStorage to store the
+        * information about the sent alarms.
+        * \param aTurnOnAt The time the device is desired to be turned on.
+        * \param aTurnOffAt The time the device is desired to be turned off.
+        * \param aDays The days to indicate if the device is wanted to be turned on/off every day (7) or
+        * just weekdays (5).
+        */
+       bool sendAlarms( QTime aTurnOnAt, QTime aTurnOffAt, int aDays = 5 );
+       //! Slot. Removes the alarms from the alarm daemon.
+       /*!
+        * Slot. Removes the alarms from the alarm daemon. Asks DeviceDataStorage to remove information
+        * about the sent alarms.
+        */
+       void removeAlarms();
+       //! Slot. Removes the alarms from the alarm daemon.
+       /*!
+        * Slot. Removes the alarms from the alarm daemon. Asks DeviceDataStorage to fetch information about
+        * the stored alarms. After removing those alarms, asks DeviceDataStorage to remove information
+        * about the alarms.
+        */
+       bool removeStoredAlarms();
+
+private:
+       //! Finds the first possible point of time to set the first alarms.
+       /*!
+        * Finds the first possible point of time to set the first alarms.
+        * \param aDays The days to indicate if the device is wanted to be turned on/off every day (7) or
+        * just weekdays (5).
+        * \param aTime The time of the turning on/off alarm.
+        * \return The date of the first alarm.
+        */
+       QDateTime findFirstTime( const int &aDays, const QTime &aTime );
+       //! Counts days from the received date to the next working day.
+       /*!
+        * Returns the day count from the received date to the next working day.
+        * \param aDateTime The date from where to count the days
+        * \return The amount of days
+        */
+       int daysToNextWorkingDay( const QDateTime &aDateTime );
+       //! Handles the result of an sent alarm.
+       /*!
+        * Handles the result of an sent alarm. Updates the received aErrorText parameter in case the alarm
+        * sending fails. If not, it updates the internal list of succesfully sent alarms.
+        * \param aCookie The result of an sent alarm.
+        * \param aErrorText The result of an sent alarm.
+        * \return True if alarm sending succeeds; otherwise, false.
+        */
+       bool handleCookie( cookie_t aCookie, QString &aErrorText );
+       //! Maps the received aErrorCode parameter to a certain error message.
+       /*!
+        * Maps the received aErrorCode parameter to a certain error message.
+        * \param aErrorCode The error code for the alarm sending failure.
+        * \return The mapped error message.
+        */
+       QString mapError( alarm_error_t aErrorCode );
+
+private:
+       DeviceDataStorage *iDataStorage;
+       QStringList iSentAlarms;
+
+};
+
+#endif /*ALARMSENDER_H_*/
diff --git a/src/IO/DeviceControl/DeviceConfigurator.cpp b/src/IO/DeviceControl/DeviceConfigurator.cpp
new file mode 100644 (file)
index 0000000..4fa515e
--- /dev/null
@@ -0,0 +1,258 @@
+#include "DeviceConfigurator.h"
+#include "DeviceDataStorage.h"
+#include "DeviceConstants.h"
+
+#include <QtDebug>
+#include <QProcess>
+
+DeviceConfigurator::DeviceConfigurator( DeviceDataStorage *aDataStorage )
+{
+       qDebug() << "DeviceConfigurator( DeviceDataStorage * )";
+       iDataStorage = aDataStorage;
+}
+
+DeviceConfigurator::~DeviceConfigurator()
+{
+       qDebug() << "~DeviceConfigurator()";
+}
+
+bool DeviceConfigurator::toggleScreenSwitchOff( bool aEnable )
+{
+       qDebug() << "DeviceConfigurator::toggleScreenSwitchOff( bool )";
+       QString command = "gconftool-2";
+       QStringList args;
+       QByteArray result;
+       QStringList confs;
+       QStringList defParams;
+       confs << "/system/osso/dsm/display/display_blank_timeout"
+       << "/system/osso/dsm/display/display_dim_timeout"
+       << "/apps/osso/applet/osso-applet-display/turn_off_display"
+       << "/apps/osso/applet/osso-applet-display/brightness_period";
+       defParams << "300" << "120" << "300" << "120";
+       QStringList origValues;
+
+       if ( !aEnable )
+       {
+               //disabling the screen "auto-switch-off" and "dimming"
+
+               //using gconftool-2 to get the current values for related configurations
+               for ( int i = 0; i < confs.size(); ++i )
+               {
+                       args.clear();
+                       args << "-g" << confs[i];
+                       if ( systemIO( command, args, result ) )
+                       {
+                               if ( result.toLong() != 0 )
+                                       origValues.append( result );
+                       }
+               }
+               if ( origValues.size() == confs.size() )  //values succesfully fetched, now trying to store them
+               {
+                       if ( !iDataStorage->storeData( iDataStorage->dataSectionToString( DeviceDataStorage::ScreenSettings ), origValues ) )
+                               emit configuringError( DeviceManager::ScreenSettingsNotStored );
+               }
+               else   //values not fetched, using the default values instead
+               {
+                       emit configuringError( DeviceManager::ScreenSettingsNotFetched );
+                       origValues.clear();
+                       for ( int i = 0; i < defParams.size(); ++i )
+                               origValues.append( defParams.at( i ) );
+               }
+
+               //using gconftool-2 to change the related configurations
+               for ( int i = 0; i < confs.size(); ++i )
+               {
+                       args.clear();
+                       args << "-s" << confs[i] << "--type=int" << "6000000";
+                       if ( !systemIO( command, args, result ) ) {
+                               emit configuringError( DeviceManager::ScreenSettingsNotChanged );
+                               return false;
+                       }
+               }
+       }
+       else
+       {
+               //setting the screen's "auto-switch-off" and "dimming" settings back as they were
+
+               //reading stored data from internal config file
+               if ( !iDataStorage->readData( iDataStorage->dataSectionToString( DeviceDataStorage::ScreenSettings ), origValues ) )
+               {
+                       //cannot read, using the default values instead
+                       emit configuringError( DeviceManager::ScreenSettingsNotFetched );
+                       for ( int i = 0; i < defParams.size(); ++i )
+                               origValues.append( defParams.at( i ) );
+               }
+               for ( int i = 0; i < origValues.size(); ++i )
+               {
+                       args.clear();
+                       args << "-s" << confs[i] << "--type=int" << origValues.at(i);
+                       if ( !systemIO( command, args, result ) ) {
+                               emit configuringError( DeviceManager::ScreenSettingsNotChanged );
+                               return false;
+                       }
+               }
+       }
+       return true;
+}
+
+bool DeviceConfigurator::toggleHWKeys( bool aEnable )
+{
+       qDebug() << "DeviceConfigurator::toggleHWKeys( bool )";
+       QStringList mceLines;
+       QStringList mceLinesNew;
+       QString mceSection = "HomeKey";
+       QStringList params;
+       params << "HomeKeyShortAction" << "HomeKeyLongAction";
+
+       // using the DeviceDataStorage exceptionally for reading data from an external conf file
+       // /etc/mce/mce.ini
+       if ( !iDataStorage->readData( mceSection, mceLines, McePath ) )
+       {
+               emit configuringError( DeviceManager::KeySettingsNotFetched );
+               return false;
+       }
+
+       if ( !aEnable )
+       {
+               // disabling the "home"-hw-key
+
+               QStringList mceLinesToStore;
+               for ( int i = 0; i < mceLines.size(); ++i )
+               {
+                       QStringList mceLine = mceLines.at( i ).split( '=' );
+                       QString param = mceLine.at( 0 ).trimmed();
+                       //check if this is the correct parameter to store and change
+                       if ( params.contains( param ) )
+                       {
+                               for ( int j = 0; j < params.size(); ++j )
+                               {
+                                       if ( params.at( j ) == param )
+                                       {
+                                               mceLinesToStore.append( mceLines.at( i ) );
+                                               mceLinesNew.append( param + "=disabled" );
+                                               break;
+                                       }
+                               }
+                       }
+                       else
+                               mceLinesNew.append( mceLines.at( i ) );
+               }
+
+               // storing the mce conf file lines
+               if ( !iDataStorage->storeData( iDataStorage->dataSectionToString( DeviceDataStorage::KeySettings ), mceLinesToStore ) )
+               {
+                       emit configuringError( DeviceManager::KeySettingsNotStored );
+                       return false;
+               }
+       }
+       else
+       {
+               // setting the "home"-hw-key settings back as they were
+
+               // reading the stored mce conf file lines
+               QStringList storedMceLines;
+               if ( !iDataStorage->readData( iDataStorage->dataSectionToString( DeviceDataStorage::KeySettings ), storedMceLines ) )
+               {
+                       emit configuringError( DeviceManager::KeySettingsNotFetched );
+                       return false;
+               }
+
+               bool paramFound = false;
+               for ( int i = 0; i < mceLines.size(); ++i )
+               {
+                       QStringList mceLine = mceLines.at( i ).split( '=' );
+                       for ( int j = 0; j < storedMceLines.size(); ++j )
+                       {
+                               QStringList storedMceLine = storedMceLines.at( j ).split( '=' );
+                               if ( storedMceLine.at( 0 ).trimmed() == mceLine.at( 0 ).trimmed() )
+                               {
+                                       mceLinesNew.append( storedMceLines.at( j ) );
+                                       paramFound = true;
+                               }
+                       }
+                       if ( !paramFound )
+                               mceLinesNew.append( mceLines.at( i ) );
+                       else
+                               paramFound = false;
+               }
+       }
+       // using the datastorage exceptionally but this time for changing data in the external conf file
+       if ( !iDataStorage->storeData( mceSection, mceLinesNew, McePath ) )
+       {
+               emit configuringError( DeviceManager::KeySettingsNotChanged );
+               return false;
+       }
+       
+       return true;
+}
+
+bool DeviceConfigurator::toggleInitScript( bool aEnable )
+{
+       QByteArray name;
+       if( !whoAmI( name ) ) {
+               emit configuringError( DeviceManager::InitScriptNotChanged );
+               return false;
+       }
+       
+       QString command = InitScript;
+       QStringList empty;
+       QByteArray result;
+       
+       if( name != "root" )
+               command.prepend( "sudo " );
+       
+       if( aEnable )
+               command.append( " install" );
+       else
+               command.append( " remove" );
+       
+       if ( !systemIO( command, empty, result ) ) {
+               emit configuringError( DeviceManager::InitScriptNotChanged );
+               return false;
+       }
+       
+       return true;
+}
+
+bool DeviceConfigurator::restartDevice()
+{
+       QString command = BinPath + DevStopper;
+       QStringList args;
+       QByteArray result;
+       args.append( "restart" );
+       if( !systemIO( command, args, result ) ) {
+               emit configuringError( DeviceManager::DeviceNotRestarted );
+               return false;
+       }
+       return true;
+}
+
+bool DeviceConfigurator::whoAmI( QByteArray &aName )
+{
+       QString command = "whoami";
+       QStringList empty;
+       if( !systemIO( command, empty, aName ) )
+               return false;
+       return true;
+}
+
+bool DeviceConfigurator::systemIO( const QString &aCommand, const QStringList &aArgs, QByteArray &aResult )
+{
+       qDebug() << "DeviceConfigurator::systemIO( QString &, QStringList &, QByteArray &)";
+       qDebug() << "Command: " << aCommand;
+       QProcess process;
+       if( !aArgs.empty() )
+               process.start( aCommand, aArgs );
+       else
+               process.start( aCommand );
+       
+       if( !process.waitForFinished() )
+               return false;
+       aResult = process.readAll();
+       if( aResult.endsWith( '\n' ) )
+               aResult.chop( 1 );
+       
+       qDebug() << "Result: " << aResult;
+       
+       return true;
+}
diff --git a/src/IO/DeviceControl/DeviceConfigurator.h b/src/IO/DeviceControl/DeviceConfigurator.h
new file mode 100644 (file)
index 0000000..30775fa
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef DEVICECONFIGURATOR_H_
+#define DEVICECONFIGURATOR_H_
+
+#include "DeviceDataStorage.h"
+
+//! DeviceControl class. Configures the device behavior.
+/*!
+ * DeviceControl class. DeviceControl class. Configures the device behavior. Updates the device system 
+ * files, activates/deactivates the application initialization script, uses the gconftool to configure
+ * some parameters of the device and uses the devstopper binary to restart the device to activate
+ * the changes. The changes it makes affect to the hardware keys, the screen dimming enabling/disabling
+ * and the automated turning on/off the device. These are all supported features of the "kiosk mode".  
+ */
+class DeviceConfigurator : public QObject 
+{
+       Q_OBJECT
+
+public:
+       //! Constructor.
+       /*!
+        * Constructor to initialize an AlarmSender instance
+        * \param aDataStorage Pointer to the DataStorage class instance.
+        */
+       DeviceConfigurator( DeviceDataStorage *aDataStorage );
+       //! Destructor.
+       virtual ~DeviceConfigurator();
+       //! Toggles the screen switching on/off and dimming options of the device.
+       /*!
+        * Toggles the screen switching on/off and dimming options of the device. Asks DeviceDataStorage to
+        * read/store the screen related original parameters. Uses systemIO( ... ) method to execute
+        * gconftool system commands to change the configurations.
+        * \param aEnable Indicates if the screen switchin off and dimming are wanted to be enabled.
+        * \return True if configuring of screen options succeeds; otherwise, false. 
+        */
+       bool toggleScreenSwitchOff( bool aEnable );
+       //! Toggles the enabling of the "home"-hardware key of the device.
+       /*!
+        * Toggles the enabling of the "home"-hardware key of the device. Asks DeviceDataStorage to
+        * read/store the hardware key related original parameters. Uses the DeviceDataStorage to manipulate
+        * the device system file /etc/mce/mce.ini to enable/disable the hw key. 
+        * \param aEnable Indicates if the "home"-hardware key is wanted to be enabled.
+        * \return True if configuring of the hw-key succeeds; otherwise, false. 
+        */
+       bool toggleHWKeys( bool aEnable );
+       //! Toggles the activation of the application initialization script.
+       /*!
+        * Toggles the activation of the application initialization script. Uses the systemIO( ... ) method 
+        * to execute the script that uses update-rc.d system command to install/remove the init script 
+        * qtmeetings-launcher. 
+        * \param aEnable Indicates if the script is wanted to be activated/deactivated
+        * \return True if activating/deactivating of the script succeeds; otherwise, false. 
+        */
+       bool toggleInitScript( bool aEnable );
+       //! Restarts the device.
+       /*!
+        * Restarts the device by using the systemIO( ... ) method to execute devstopper executable.
+        * \return True if resrating of the device succeeds; otherwise, false.
+        */
+       bool restartDevice();
+       //! Resolves the currently used account of the device.
+       /*!
+        * Resolves the currently used account of the device by using the systemIO( ... ) method to execute 
+        * whoami system command.
+        * \return True if resolving the account succeeds; otherwise, false.
+        */
+       static bool whoAmI( QByteArray &aName );
+       //! Consists and executes a system command and stores the received output.
+       /*!
+        * Consists and executes a system command and stores the received output.
+        * \param aCommand The whole system command or just the "binary"-part of the command
+        * \param aArgs The possible arguments for the "binary"
+        * \param aResult The place to put the output of the command 
+        * \return True if executing the system command succeeds; otherwise, false.
+        */
+       static bool systemIO( const QString &aCommand, const QStringList &aArgs, QByteArray &aResult );
+
+signals:
+       //! Signal. Emitted if error occured during configuring the device.
+       /*!
+        * Signal. Emitted if error occured during configuring the device.
+        * \param aErrorCode The error code.
+        */
+       void configuringError( DeviceManager::ErrorCode aErrorCode );
+
+private:
+       DeviceDataStorage *iDataStorage;
+};
+
+#endif /*DEVICECONFIGURATOR_H_*/
diff --git a/src/IO/DeviceControl/DeviceConstants.h b/src/IO/DeviceControl/DeviceConstants.h
new file mode 100644 (file)
index 0000000..9f82a43
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef DEVICECONSTANTS_H_
+#define DEVICECONSTANTS_H_
+
+static const QString BinPath = "/usr/bin/";
+static const QString DevStopper = "qtmeetings-devstopper";
+static const QString RenameScript = "qtmeetings-rename";
+static const QString InitScript = "qtmeetings-updatercd";
+static const QString DataStoragePath = "/usr/var/qtmeetings.txt";
+static const QString McePath = "/etc/mce/mce.ini";
+
+#endif /*DEVICECONSTANTS_H_*/
diff --git a/src/IO/DeviceControl/DeviceDataStorage.cpp b/src/IO/DeviceControl/DeviceDataStorage.cpp
new file mode 100644 (file)
index 0000000..45250fb
--- /dev/null
@@ -0,0 +1,210 @@
+#include "DeviceDataStorage.h"
+#include "DeviceConfigurator.h"
+
+#include <QtDebug>
+#include <QFile>
+#include <QHash>
+#include <QStringList>
+#include <QTextStream>
+
+DeviceDataStorage::DeviceDataStorage()
+{
+       qDebug() << "DeviceDataStorage::DeviceDataStorage()";
+}
+
+bool DeviceDataStorage::initDataStorage()
+{
+       qDebug() << "DeviceDataStorage::initDataStorage()";
+       //create the conf file if not yet created
+       QFile file( DataStoragePath );  
+       
+       if ( !file.exists() ) {
+               
+               // to avoid possible permission errors, create temp data file and rename it after finished
+               QString DataStoragePathTmp = "/tmp/" + ( DataStoragePath.split( '/' ) ).back() + ".tmp";
+               QFile fileTmp( DataStoragePathTmp );
+               
+               if ( !fileTmp.open( QIODevice::WriteOnly | QIODevice::Text ) 
+                               || !fileTmp.setPermissions( QFile::ReadUser | QFile::WriteUser | QFile::ReadGroup | QFile::WriteGroup | QFile::ReadOwner | QFile::WriteOwner | QFile::ReadOther | QFile::WriteOther ) ) {
+                       emit dataStorageInitFailed( DeviceManager::FileCreationFailed );
+                       return false;
+               }
+               else {
+                       fileTmp.close();
+                       file.close();
+                       if ( !renameFile( DataStoragePathTmp, DataStoragePath ) )
+                               return false;
+               }
+       }
+       return true;
+}
+
+DeviceDataStorage::~DeviceDataStorage()
+{
+       qDebug() << "DeviceDataStorage::~DeviceDataStorage()";
+}
+
+bool DeviceDataStorage::readData( const QString aSection, QStringList &aData, const QString &aFilename )
+{
+       qDebug() << "DeviceDataStorage::readData( QString, QStringList &, const QString &)";
+       QHash<QString, QStringList> allData;
+       QStringList sectionOrder; //not needed in this case
+
+       if ( !readDataFromFile( allData, sectionOrder, aFilename ) )
+               return false;
+
+       QHash<QString, QStringList>::iterator i;
+       for ( i = allData.begin(); i != allData.end(); ++i )
+       {
+               if ( i.key() == aSection )
+               {
+                       aData = i.value();
+                       break;
+               }
+       }
+       return true;
+}
+
+bool DeviceDataStorage::storeData( QString aSection, const QStringList &aData, const QString &aFilename )
+{
+       qDebug() << "DeviceDataStorage::storeData( QString, const QStringList &, const QString & )";
+       QHash<QString, QStringList> allData;
+       QHash<QString, QStringList> allDataNew;
+       QStringList sectionOrder;
+       bool sectionFound = false;
+
+       if ( !readDataFromFile( allData, sectionOrder, aFilename ) )
+               return false;
+
+       // replace data under the certain section
+       QHash<QString, QStringList>::iterator i;
+       for ( i = allData.begin(); i != allData.end(); ++i ) {
+               if ( i.key() == aSection ) {
+                       allDataNew.insert( i.key(), aData );
+                       sectionFound = true;
+               }
+               else
+                       allDataNew.insert( i.key(), i.value() );
+       }
+
+       // data with this section is not yet in the file
+       if ( !sectionFound ) {
+               allDataNew.insert( aSection, aData );
+               sectionOrder.append( aSection );
+       }
+       
+       // to avoid possible permission errors, write the data to new file
+       QString filenameTmp = "/tmp/" + ( aFilename.split( '/' ) ).back() + ".tmp";
+
+       if ( !writeDataToFile( allDataNew, sectionOrder, filenameTmp ) )
+               return false;
+       if ( !renameFile( filenameTmp, aFilename ) )
+               return false;
+
+       return true;
+}
+
+bool DeviceDataStorage::renameFile( const QString &aFilenameTmp, const QString &aFilename )
+{
+       qDebug() << "DeviceDataStorage::renameFile( const QString &, const QString & )";
+       
+       QByteArray result;
+       if( !DeviceConfigurator::whoAmI( result ) )
+               return false;
+       
+       QString command;
+       QStringList empty;
+       if( result != "root" )
+               command = "sudo ";
+       
+       command.append( BinPath + RenameScript + " " + aFilenameTmp + " " + aFilename );
+       
+       if( !DeviceConfigurator::systemIO( command, empty, result ) )
+               return false;
+
+       return true;
+}
+
+bool DeviceDataStorage::readDataFromFile( QHash<QString, QStringList> &aDataHash, QStringList &aSectionOrder, const QString &aFilename )
+{
+       qDebug() << "DeviceDataStorage::readDataFromFile( QHash<QString,QStringList> &, const QString & )";
+       QFile file( aFilename );
+
+       if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
+               return false;
+
+       QTextStream in( &file );
+       QString dataSection = "";
+       QStringList data;
+       bool firstSection = true;
+
+       while ( !in.atEnd() )
+       {
+               QString line = in.readLine();
+               if ( line.at( 0 ) == QChar( '[' ) && line.at( line.length() - 1 ) == QChar( ']' ) )
+               {
+                       if ( !firstSection )
+                               aDataHash.insert( dataSection, data );
+                       line.replace( QString( "[" ), QString( "" ) );
+                       line.replace( QString( "]" ), QString( "" ) );
+                       dataSection = line;
+                       data.clear();
+                       firstSection = false;
+                       aSectionOrder.append( dataSection );
+               }
+               else
+                       data.append( line );
+       }
+       if ( dataSection != "" )        //the file wasn't empty, saving the last section
+               aDataHash.insert( dataSection, data );
+       file.close();
+
+       return true;
+}
+
+bool DeviceDataStorage::writeDataToFile( const QHash<QString, QStringList> &aDataHash, const QStringList &aSectionOrder, const QString &aFilename )
+{
+       qDebug() << "DeviceDataStorage::writeDataToFile( QHash<QString,QStringList> &, const QString & )";
+       
+       QFile file( aFilename );
+
+       if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) )
+               return false;
+
+       QTextStream out( &file );
+
+       QHash<QString, QStringList>::const_iterator i;
+       for ( int j = 0; j < aSectionOrder.size(); ++j )
+       {
+               for ( i = aDataHash.begin(); i != aDataHash.end(); ++i )
+               {
+                       if ( aSectionOrder.at( j ) == i.key() )
+                       {
+                               out << "[" << i.key() << "]\n";
+                               QStringList list = i.value();
+                               for ( int j = 0; j < list.size(); ++j )
+                                       out << list.at( j ) << "\n";
+                               break;
+                       }
+               }
+       }
+       file.close();
+
+       return true;
+}
+
+QString DeviceDataStorage::dataSectionToString( DataSection aDataSection )
+{
+       qDebug() << "DeviceDataStorage::dataSectionToString( DataSection )";
+       switch ( aDataSection )
+       {
+               case Alarms:
+                       return "Alarms";
+               case ScreenSettings:
+                       return "ScreenSettings";
+               case KeySettings:
+                       return "KeySettings";
+               default: //DeviceMode
+                       return "DeviceMode";
+       }
+}
diff --git a/src/IO/DeviceControl/DeviceDataStorage.h b/src/IO/DeviceControl/DeviceDataStorage.h
new file mode 100644 (file)
index 0000000..a8ca1ad
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef DEVICEDATASTORAGE_H_
+#define DEVICEDATASTORAGE_H_
+
+#include "DeviceManager.h"
+#include "DeviceConstants.h"
+
+#include <QObject>
+
+#include <QHash>
+#include <QStringList>
+
+//! DeviceControl class. Reads and stores data form/to the internal data storage.
+/*!
+ * DeviceControl class. Reads and stores data form/to the internal data storage. Datastorage is an
+ * ini file which contains information about sent alarms, device screen settings, device hardware key
+ * settings and current application operation mode. The class can be used to manipulate any other ini
+ * typed files as well.
+ */
+class DeviceDataStorage : public QObject
+{
+       Q_OBJECT
+
+public:
+       //! Enumeration of data sections
+       /*!
+        * Enumeration of data sections
+        */
+       enum DataSection
+       {
+               Alarms, /*!< Alarms section. */
+               ScreenSettings, /*!< Screen option section. */
+               KeySettings, /*!< HW key option section. */
+               DeviceMode /*!< Device mode section. */
+       };
+
+public:
+       //! Constructor.
+       /*!
+        * Constructor to initialize a DeviceDataStorage instance
+        */
+       DeviceDataStorage();
+       //! Destructor.
+       virtual ~DeviceDataStorage();
+       //! Creates the internal data storage file.
+       /*!
+        * Creates the internal data storage file.
+        * \return True if file creation succeeds; otherwise false.
+        */
+       bool initDataStorage();
+       //! Stores data to an ini file.
+       /*!
+        * Stores data to an ini file. Calls readDataFromFile( ... ) method to receive the current content of
+        * the file and replaces the data under the certain section or creates a completely new section with
+        * the data. After that it calls the writeDataToFile( ... ) to store the modified content.
+        * \param aSection The data section under which the data needs to be stored.
+        * \param aData The data to be stored.
+        * \param aFilename The file to modify.
+        * \return True if file modifying succeeds; otherwise false.
+        */
+       bool storeData( QString aSection, const QStringList &aData, const QString &aFilename = DataStoragePath );
+       //! Reads data from an ini file.
+       /*!
+        * Reads data from an ini file. Calls readDataFromFile( ... ) method to receive the current content
+        * of the file and finds the data under the certain section and stores it to the aData parameter.
+        * \param aSection The data section under which the data needs to be red.
+        * \param aData The parameter to place the found data.
+        * \param aFilename The file to read.
+        * \return True if file reading succeeds; otherwise false.
+        */
+       bool readData( QString aSection, QStringList &aData, const QString &aFilename = DataStoragePath );
+       //! Transform the data section enum value to QString.
+       /*!
+        * Transform the data section enum value to QString. Is used only when handling the internal data
+        * storage file.
+        * \param aSection The data section enum value to be transformed.
+        * \return The QString value that corresponds the enum value.
+        */     
+       QString dataSectionToString( DataSection aDataSection );
+
+signals:
+       //! Signal. Emitted if error occured during internal data storage file creation.
+       /*!
+        * Signal. Emitted if error occured during internal data storage file creation.
+        * \param aErrorCode The error code.
+        */
+       void dataStorageInitFailed( DeviceManager::ErrorCode aErrorCode );
+
+private:
+       //! Replaces the original ini file with the temporary ini file that conatins the required changes.
+       /*!
+        * Replaces the original ini file with the temporary ini file that conatins the required changes.
+        * Uses the static DeviceConfigurator method systemIO( ... ) to execute the rename script
+        * qtmeetings-rename.
+        * \param aFilenameTmp The temporary file.
+        * \param aFilename The actual file.
+        * \return True if file renaming succeeds; otherwise false.
+        */
+       bool renameFile( const QString &aFilenameTmp, const QString &aFilename );
+       //! Reads data from an ini file.
+       /*!
+        * Reads data from an ini file. Does the actual job to read the data from the ini file.
+        * \param aDataHash Place to put the content of the file. Key of the hash is for the section and 
+        * value is for the actual data.
+        * \param aSectionOrder Place to keep track of the sections and their orders in the file. QHash doesn't
+        * keep track of the order of the keys.
+        * \param aFilename The file to read.
+        * \return True if file reading succeeds; otherwise false.
+        */
+       bool readDataFromFile( QHash<QString, QStringList> &aDataHash, QStringList &aSectionOrder, const QString &aFilename );
+       //! Stores data to an ini file.
+       /*!
+        * Stores data to an ini file. Does the actual job to store the data to the ini file.
+        * \param aDataHash To read the data to be stored. Key of the hash is for the section and value is for
+        * the actual data.
+        * \param aSectionOrder Contains the correct oredr of the sections to be stored.
+        * \param aFilename The file to store the data.
+        * \return True if file writing succeeds; otherwise false.
+        */
+       bool writeDataToFile( const QHash<QString, QStringList> &aDataHash, const QStringList &aSectionOrder, const QString &aFilename );
+
+};
+
+#endif /*DEVICEDATASTORAGE_H_*/
diff --git a/src/IO/DeviceControl/DeviceManager.cpp b/src/IO/DeviceControl/DeviceManager.cpp
new file mode 100644 (file)
index 0000000..ed5a66a
--- /dev/null
@@ -0,0 +1,241 @@
+#include "DeviceManager.h"
+#include "AlarmSender.h"
+#include "HWKeyListener.h"
+#include "StartupSettings.h"
+#include "DeviceDataStorage.h"
+#include "DeviceConfigurator.h"
+
+#include <QtDebug>
+#include <QStringList>
+
+DeviceManager::DeviceManager( StartupSettings *aSettings )
+{
+       qDebug() << "DeviceManager::DeviceManager( StartupSettings * )";
+
+       iSettings = aSettings;
+       iSendErrorMessages = true;
+}
+
+DeviceManager::~DeviceManager()
+{
+       qDebug() << "DeviceManager::~DeviceManager()";
+}
+
+void DeviceManager::initDeviceManager()
+{
+       qDebug() << "DeviceManager::init()";
+       iDataStorage = new DeviceDataStorage();
+       connect( iDataStorage, SIGNAL( dataStorageInitFailed( DeviceManager::ErrorCode ) ),
+                       this, SLOT( errorSender( DeviceManager::ErrorCode ) ) );
+
+       iAlarmSender = new AlarmSender( iDataStorage );
+       connect( iAlarmSender, SIGNAL( alarmSendingFailed( DeviceManager::ErrorCode, const QString& ) ),
+                       this, SLOT( errorSender( DeviceManager::ErrorCode, const QString& ) ) );
+
+       iConfigurator = new DeviceConfigurator( iDataStorage );
+       connect( iConfigurator, SIGNAL( configuringError( DeviceManager::ErrorCode ) ),
+                       this, SLOT( errorSender( DeviceManager::ErrorCode ) ) );
+
+       if ( !iDataStorage->initDataStorage() || !setCurrentOperationMode() )
+               iMode = EmptyMode;
+
+       iHWKeyListener = new HWKeyListener();
+       handleKeyPresses( true );
+}
+
+DeviceManager::OperationMode DeviceManager::currentOperationMode()
+{
+       return iMode;
+}
+
+QString DeviceManager::operationModeToString( OperationMode aMode )
+{
+       switch ( aMode )
+       {
+               case KioskMode:
+                       return "Kiosk-mode";
+               case StandAloneMode:
+                       return "Stand Alone-mode";
+               default:
+                       return "";
+       }
+}
+
+void DeviceManager::changeMode( bool aChange )
+{
+       qDebug() << "void DeviceManager::changeMode()";
+       if( !aChange ) {
+               handleKeyPresses( true );
+               return;
+       }
+
+       switch ( iMode )
+       {
+               case EmptyMode:
+                       // error occured. Mode cannot be changed
+                       errorSender( ModeNotFetched );
+                       handleKeyPresses( true );
+                       break;
+               case StandAloneMode:
+
+                       // change to KioskMode
+
+                       // check if auto turn on/off functionality enabled and send turn on/off alarm events to alarm daemon
+                       if ( iSettings->isPowersavingEnabled() )
+                       {
+                               if ( !iAlarmSender->sendAlarms( iSettings->turnOnAt(), iSettings->turnOffAt() ) )
+                               {
+                                       handleKeyPresses( true );
+                                       return; //this is critical so returning if no success
+                               }
+                       }
+
+                       // - disable the certain hw keys (only "home"-hw-key at the moment)
+                       // - register init script to launch the application when ever the device is launched
+                       // - disable the screen "auto-switch-off" and "dimming"
+                       // - store info about the new operation mode
+                       if ( !iConfigurator->toggleHWKeys( false ) ||
+                                 !iConfigurator->toggleInitScript( true ) ||
+                                 !iConfigurator->toggleScreenSwitchOff( false ) ||
+                                 !this->storeOperationMode( KioskMode ) ||
+                                 !iConfigurator->restartDevice() )
+                       {
+
+                               // we have to roll back if something fails
+                               // of course rolling back may fail as well but it is impossible to catch
+                               iSendErrorMessages = false;
+                               iAlarmSender->removeAlarms();
+                               iConfigurator->toggleHWKeys( true );
+                               iConfigurator->toggleInitScript( false );
+                               iConfigurator->toggleScreenSwitchOff( true );
+                               iSendErrorMessages = true;
+                               handleKeyPresses( true );
+                               return;
+                       }
+                       break;
+
+               case KioskMode:
+                       // change to StandAloneInProgress mode
+
+                       // - enable the certain hw keys (only "home"-hw-key at the moment)
+                       // - unregister the init script
+                       // - enable the screen "auto-switch-off" and "dimming"
+                       // - store info about the new operation mode
+                       if (    !iConfigurator->toggleHWKeys( true ) ||
+                                 !iConfigurator->toggleScreenSwitchOff( true ) ||
+                                 !this->storeOperationMode( StandAloneModeInProgress ) ||
+                                 !iAlarmSender->removeStoredAlarms() ||
+                                 !iConfigurator->restartDevice() )
+                       {
+                               // we have to roll back if something fails
+                               // of course rolling back may fail as well but it is impossible to catch
+                               iSendErrorMessages = false;
+                               iConfigurator->toggleHWKeys( false );
+                               iConfigurator->toggleInitScript( true );
+                               iConfigurator->toggleScreenSwitchOff( false );
+                               this->storeOperationMode( KioskMode );
+                               iSendErrorMessages = true;
+                               handleKeyPresses( true );
+                               return;
+                       }
+
+                       break;
+               default: // StandAloneModeInProgress should never come in question
+                       break;
+       }
+}
+
+bool DeviceManager::setCurrentOperationMode()
+{
+       qDebug() << "DeviceManager::currentOperationMode()";
+       QStringList modeResult;
+       if ( !iDataStorage->readData( iDataStorage->dataSectionToString( DeviceDataStorage::DeviceMode ), modeResult ) )
+       {
+               errorSender( ModeNotFetched );
+               return false;
+       }
+       else
+       {
+               if ( !modeResult.empty() )
+               {
+                       iMode = ( OperationMode )modeResult.at( 0 ).toInt();
+                       if ( iMode == StandAloneModeInProgress )
+                       {
+                               if ( !finalizeStandAloneMode() )
+                                       iMode = EmptyMode;
+                               else
+                                       iMode = StandAloneMode;
+                       }
+               }
+               else //this must be the first time, so no mode info saved yet
+                       iMode = StandAloneMode;
+       }
+       return true;
+}
+
+bool DeviceManager::storeOperationMode( OperationMode aMode )
+{
+       qDebug() << "DeviceManager::storeOperationMode( const OperationMode & )";
+       QStringList modeStrList;
+       QString str;
+       modeStrList.append( str.append( QString( "%1" ).arg( aMode ) ) );
+       if ( !iDataStorage->storeData( iDataStorage->dataSectionToString( DeviceDataStorage::DeviceMode ), modeStrList ) )
+       {
+               errorSender( ModeNotStored );
+               return false;
+       }
+       return true;
+}
+
+bool DeviceManager::finalizeStandAloneMode()
+{
+       qDebug() << "DeviceManager::finalizeStandAloneMode()";
+       if ( !storeOperationMode( StandAloneMode ) || !iConfigurator->toggleInitScript( false ) )
+               return false;
+       return true;
+}
+
+void DeviceManager::handleKeyPresses( bool aHandle )
+{
+       qDebug() << "DeviceManager::handleKeyPresses( bool )";
+       if ( !aHandle )
+               disconnect( iHWKeyListener, SIGNAL( HWKeyFullScreenPressed() ), this, SLOT( HWKeyFullScreenPressed() ) );
+       else
+               connect( iHWKeyListener, SIGNAL( HWKeyFullScreenPressed() ), this, SLOT( HWKeyFullScreenPressed() ) );
+}
+
+void DeviceManager::HWKeyFullScreenPressed()
+{
+       qDebug() << "DeviceManager::HWKeyFullScreenPressed()";
+       
+       // no more key presses before this one is handled
+       handleKeyPresses( false );
+       
+       OperationMode nextMode;
+       switch ( iMode )
+       {
+               case KioskMode:
+                       nextMode = StandAloneMode;
+                       break;
+               case StandAloneMode:
+                       nextMode = KioskMode;
+                       break;
+               default:
+                       nextMode = EmptyMode;
+                       break;
+       }
+       if ( nextMode != EmptyMode )
+               emit changeModeOrdered( nextMode );
+       else
+               handleKeyPresses( true );
+}
+
+void DeviceManager::errorSender( DeviceManager::ErrorCode aErrorCode, const QString &aAddInfo )
+{
+       qDebug() << "DeviceManager::errorSender( ErrorCode, QString & )";
+       qDebug() << "DeviceManager::errorSender: aErrorCode == " << aErrorCode << " " << aAddInfo;
+       if ( !iSendErrorMessages )
+               return;
+
+       emit error( ERROR_BASE + ( int )aErrorCode, aAddInfo ); 
+}
diff --git a/src/IO/DeviceControl/DeviceManager.h b/src/IO/DeviceControl/DeviceManager.h
new file mode 100644 (file)
index 0000000..f3f89dc
--- /dev/null
@@ -0,0 +1,171 @@
+#ifndef DEVICEMANAGER_H_
+#define DEVICEMANAGER_H_
+
+#include <QObject>
+#include <QStringList>
+
+class AlarmSender;
+class HWKeyListener;
+class StartupSettings;
+class DeviceDataStorage;
+class DeviceConfigurator;
+
+static const int ERROR_BASE=200;
+
+//! DeviceControl class. The main class of the DeviceControl.
+/*!
+ * DeviceControl class. The main class of the DeviceControl. Responsible to communicate between the
+ * BusinessLogic and the device. Takes care of the operation mode changes of the application.
+ */
+class DeviceManager : public QObject
+{
+       Q_OBJECT
+
+public:
+       //! Enumeration of device modes
+       /*!
+        * Enumeration of device modes
+        */
+       enum OperationMode
+       {
+               KioskMode, /*!< Device is in kiosk mode. */
+               StandAloneModeInProgress, /*!< Device is in stand alone mode. */
+               StandAloneMode, /*!< Device is in stand alone mode. */
+               EmptyMode /*!< Application cannot read the mode. */
+       };
+
+       //! Enumeration of errors
+       /*!
+        * Enumeration of errors
+        */
+       enum ErrorCode
+       {
+               FileCreationFailed, /*!< File couldn't be created. */
+               OldAlarmsNotRemoved, /*!< Previously sent old alarm events cannot be removed. */
+               NewAlarmsNotSent, /*!< New alarms cannot be sent. */
+               NewAlarmsNotStored, /*!< Information about new sent alarms cannot be stored. */
+               ScreenSettingsNotStored, /*!< Configuration parameters of screen options cannot be stored. */
+               ScreenSettingsNotFetched, /*!< Configuration parameters of screen options cannot be fetched. */
+               ScreenSettingsNotChanged, /*!< Configuration parameters of screen options cannot be changed. */
+               KeySettingsNotFetched, /*!< Configuration parameters of hw key options cannot be fetched. */
+               KeySettingsNotStored, /*!< Configuration parameters of hw key options cannot be stored. */
+               KeySettingsNotChanged, /*!< Configuration parameters of hw key options cannot be changed. */
+               InitScriptNotChanged, /*!< Init script to auto launch the application was not registered/unregistered */
+               ModeNotFetched, /*!< Information about the current operation mode cannot be fetched */
+               ModeNotStored, /*!< Information about the new opration mode cannot be stored */
+               DeviceNotRestarted /*!< Device cannot be restarted */
+       };
+
+public:
+       //! Constructor.
+       /*!
+        * Constructor to initialize a DeviceManager instance.
+        * \param aSettings Pointer to the start up configuration settings.
+        */
+       DeviceManager( StartupSettings *aSettings );
+       //! Destructor.
+       virtual ~DeviceManager();
+       //! Creates instances of AlarmSender, DeviceConfigurator, DeviceDataStorage and HWKeyListener classes.
+       /*!
+        * Creates instances of AlarmSender, DeviceConfigurator, DeviceDataStorage and HWKeyListener classes.
+        * Connects their signals to the correct errorSender( ... ) slot.
+        */
+       void initDeviceManager();
+       //! Gets the current operation mode.
+       /*!
+        * Gets the current operation mode of the application.
+        * \return enum value of the current operation mode.
+        */
+       DeviceManager::OperationMode currentOperationMode();
+       //! Gets the string value of an operation mode.
+       /*!
+        * Gets the string value of an operation mode.
+        * \param aMode The enum value of the operation mode.
+        * \return QString value of the current operation mode.
+        */
+       QString operationModeToString( OperationMode aMode );
+
+signals:
+       //! Signal. Emitted if user tries to change the operation mode.
+       /*!
+        * Signal. Emitted if user tries to change the operation mode.
+        * \param aMode The operation mode that user wants to activate.
+        */
+       void changeModeOrdered( DeviceManager::OperationMode aMode );
+       //! Signal. Emitted if an error happens.
+       /*!
+        * Signal. Emitted if an error happens.
+        * \param aCode An error code defined by DeviceManager.
+        * \param aAddInfo Possible additional information.
+        */
+       void error( int aCode, const QString &aAddInfo );
+
+public slots:
+       //! Slot. Changes the operation mode.
+       /*!
+        * Slot. Changes the operation mode.
+        * \param aChange To indicate if the mode should be changed or not
+        */
+       void changeMode( bool aChange );
+
+private slots:
+       //! Slot. Handles "full screen"-hardware key presses.
+       /*!
+        * Slot. Handles "full screen"-hardware key presses. Checks the current operation mode and concludes
+        * the next (desired) operation mode to be set. Emits a changeModeOrdered( DeviceManager::OperationMode )
+        * signal.
+        */
+       void HWKeyFullScreenPressed();
+       //! Slot. Sends errors.
+       /*!
+        * Slot. Sends errors.
+        * \param aErrorCode The error code.
+        * \param aAddInfo The possible additional error text.
+        */
+       void errorSender( DeviceManager::ErrorCode aErrorCode, const QString &aAddInfo = "" );
+
+private:
+       //! Updates the internal indicator of the current operation mode.
+       /*!
+        * Updates the internal indicator of the current operation mode by asking the DeviceDataStorage to
+        * read it from the internal data storage. Calls finalizeStandAloneMode() method in case the mode is
+        * StandAloneModeInProgress.
+        * \return True if operation mode fetching succeeds; otherwise, false.
+        */
+       bool setCurrentOperationMode();
+       //! Stores the current operation mode.
+       /*!
+        * Stores the current operation mode by asking the DeviceDataStorage to write it to the internal
+        * data storage.
+        * \param aMode The operation mode that user wants to activate.
+        * \return True if operation mode storing succeeds; otherwise, false.
+        */
+       bool storeOperationMode( OperationMode aMode );
+       //! Asks DeviceConfigurator to remove the deactivate script of the application.
+       /*!
+        * Asks DeviceConfigurator to remove the deactivate script of the application. Also asks
+        * DeviceDataStorage to store the current operation mode (StandAloneMode) .
+        * \return True if operation mode storing and deactivation of the init script succeed; otherwise, false.
+        */
+       bool finalizeStandAloneMode();
+       //! Connects/disconnects the HWKeyListener signals to the private HWKeyFullScreenPressed() slot.
+       /*!
+        * Connects/disconnects the HWKeyListener signals to the private HWKeyFullScreenPressed() slot. In case
+        * a signal is caught the connection is disabled until the signal handling is finished.
+        * \param aHandle indicates if the signals should be connected or not.
+        */
+       void handleKeyPresses( bool aHandle );
+
+private:
+       AlarmSender *iAlarmSender;
+       HWKeyListener *iHWKeyListener;
+       StartupSettings *iSettings;
+       DeviceDataStorage *iDataStorage;
+       DeviceConfigurator *iConfigurator;
+
+       OperationMode iMode;
+       bool iSendErrorMessages;
+
+};
+
+#endif /*DEVICEMANAGER_H_*/
diff --git a/src/IO/DeviceControl/HWKeyListener.cpp b/src/IO/DeviceControl/HWKeyListener.cpp
new file mode 100644 (file)
index 0000000..2029f79
--- /dev/null
@@ -0,0 +1,39 @@
+#include "HWKeyListener.h"
+
+#include <QCoreApplication>
+#include <QKeyEvent>
+#include <QtDebug>
+
+HWKeyListener::HWKeyListener() : QObject()
+{
+       iApplication = QCoreApplication::instance( );
+       iApplication->installEventFilter( this );
+}
+
+HWKeyListener::~HWKeyListener()
+{
+
+}
+
+bool HWKeyListener::eventFilter( QObject*, QEvent* e )
+{
+       if ( e->type() == QEvent::KeyPress )
+       {
+               QKeyEvent *keyEvent = static_cast<QKeyEvent *>( e );
+               switch ( keyEvent->key() )
+               {
+                       case Qt::Key_F6:
+                               qDebug() << "HW key full screen pressed";
+                               emit HWKeyFullScreenPressed();
+                               break;
+                       case Qt::Key_F7:
+                               qDebug() << "HW key zoom out pressed";
+                               emit HWKeyZoomOutPressed();
+                               break;
+                       case Qt::Key_F8:
+                               qDebug() << "HW key zoom in pressed";
+                               emit HWKeyZoomInPressed();
+               }
+       }
+       return false;
+}
diff --git a/src/IO/DeviceControl/HWKeyListener.h b/src/IO/DeviceControl/HWKeyListener.h
new file mode 100644 (file)
index 0000000..15e2966
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef HWKEYLISTENER_H_
+#define HWKEYLISTENER_H_
+
+#include <QObject>
+
+class QCoreApplication;
+
+//! DeviceControl class. Monitors hardware key presses.
+/*!
+ * DeviceControl class. Listens the hardware key presses and emits a related signal for the essential ones.
+ */
+class HWKeyListener : public QObject
+{
+       Q_OBJECT
+public:
+       //! Constructor.
+       /*!
+        * Constructor for HWKeyListener class
+        */
+       HWKeyListener();
+       //! Destructor.
+       virtual ~HWKeyListener();
+
+signals:
+       //! Signals if user presses F6 (Full screen) hardware key
+       /*!
+        * The signal is emitted if user presses F6 (Full Screen) hardware key
+        */
+       void HWKeyFullScreenPressed( );
+       //! Signals if user presses F7 (Zoom out) hardware key
+       /*!
+        * The signal is emitted if user presses F7 (Zoom out) hardware key
+        */
+       void HWKeyZoomOutPressed( );
+       //! Signals if user presses F8 (Zoom in) hardware key
+       /*!
+        * The signal is emitted if user presses F8 (Zoom in) hardware key
+        */
+       void HWKeyZoomInPressed( );
+
+protected:
+       //! Monitors user's interaction and controls functionality based on user's actions.
+       /*!
+        * Monitors user's interaction and controls functionality based on user's actions.
+        */
+       virtual bool eventFilter( QObject *aWatched_object, QEvent *e );
+
+private:
+       QCoreApplication *iApplication;
+
+};
+
+#endif /*HWKEYLISTENER_H_*/
diff --git a/src/UserInterface/Components/DigitalTimeDisplayWidget.cpp b/src/UserInterface/Components/DigitalTimeDisplayWidget.cpp
new file mode 100644 (file)
index 0000000..3b06ed5
--- /dev/null
@@ -0,0 +1,55 @@
+#include "DigitalTimeDisplayWidget.h"\r
+#include <QLCDNumber>\r
+#include <QVBoxLayout>\r
+\r
+//const QString timeFormat( "hh:mm" ); //time display format\r
+\r
+DigitalTimeDisplayWidget::DigitalTimeDisplayWidget( QTime aNow, QString aFormat, QWidget *aParent ) :\r
+               TimeDisplayWidget( aNow, aParent ), iTimeFormat( aFormat )\r
+{\r
+       iDisplay = new QLCDNumber( this );\r
+       iDisplay->setSegmentStyle( QLCDNumber::Flat );\r
+\r
+       QVBoxLayout *layout = new QVBoxLayout;\r
+       layout->addWidget( iDisplay );\r
+       layout->setMargin( 0 );\r
+       setLayout( layout );\r
+\r
+       showTime();\r
+}\r
+\r
+DigitalTimeDisplayWidget::~DigitalTimeDisplayWidget()\r
+{\r
+       delete iDisplay;\r
+       iDisplay = 0;\r
+}\r
+\r
+void DigitalTimeDisplayWidget::setFrameVisible( bool aVisible )\r
+{\r
+       if ( aVisible )\r
+       {\r
+               iDisplay->setFrameShape( QFrame::Box );\r
+       }\r
+       else\r
+       {\r
+               iDisplay->setFrameShape( QFrame::NoFrame );\r
+       }\r
+}\r
+\r
+void DigitalTimeDisplayWidget::setSize( int aWidth, int aHeight )\r
+{\r
+       if ( aWidth > 0 && aHeight > 0 )\r
+       {\r
+               setFixedSize( aWidth, aHeight );\r
+       }\r
+}\r
+\r
+void DigitalTimeDisplayWidget::showTime()\r
+{\r
+       iDisplay->display( time().toString( iTimeFormat ) );\r
+}\r
+\r
+void DigitalTimeDisplayWidget::setFont( const QFont &aFont )\r
+{\r
+       iDisplay->setFont( aFont );\r
+}\r
diff --git a/src/UserInterface/Components/DigitalTimeDisplayWidget.h b/src/UserInterface/Components/DigitalTimeDisplayWidget.h
new file mode 100644 (file)
index 0000000..4273f8b
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef DIGITALTIMEDISPLAYWIDGET_H_\r
+#define DIGITALTIMEDISPLAYWIDGET_H_\r
+\r
+#include "TimeDisplayWidget.h"\r
+\r
+class QLCDNumber;\r
+\r
+//! Userinterface class. Displays time in a digital display.\r
+/*!\r
+ * Userinterface class. Displays time in a digital display. Inherits TimeDisplayWidget and diplays time in\r
+ * QLCDNumber display.\r
+ */\r
+class DigitalTimeDisplayWidget : public TimeDisplayWidget\r
+{\r
+       Q_OBJECT\r
+\r
+public:\r
+       //! Constructor.\r
+       /*!\r
+        * Constructor to initialize a DigitalTimeDisplayWidget instance.\r
+        * \param aNow Current time.\r
+        * \param aFormat Time display format.\r
+        * \param aParent Parent widget. Optional.\r
+        */\r
+       DigitalTimeDisplayWidget( QTime aNow, QString aFormat, QWidget *aParent = 0 );\r
+       //! Destructor.\r
+       virtual ~DigitalTimeDisplayWidget();\r
+\r
+       //! Sets frame visibility.\r
+       /*!\r
+        * Setst the visibility of the frame around this widget.\r
+        * \param aVisible True, if frame is drawn, otherwise false.\r
+        */\r
+       virtual void setFrameVisible( bool aVisible );\r
+       //! Sets size.\r
+       /*!\r
+        * Sets the size.\r
+        * \param aWidth Width of the widget on the screen.\r
+        * \param aHeight Height of the widget on the screen.\r
+        */\r
+       virtual void setSize( int aWidth, int aHeight );\r
+       //! Sets Font\r
+       /*!\r
+        * Sets the font.\r
+        * \param aFont The new font.\r
+        */\r
+       virtual void setFont( const QFont &aFont );\r
+\r
+protected:\r
+       //! Displays the time.\r
+       /*!\r
+        * Displays the time in LCD number display.\r
+        */\r
+       virtual void showTime();\r
+\r
+private:\r
+       //! Display to show the time.\r
+       QLCDNumber *iDisplay;\r
+       //! Format used to show time.\r
+       QString iTimeFormat;\r
+\r
+};\r
+\r
+#endif /*DIGITALTIMEDISPLAYWIDGET_H_*/\r
diff --git a/src/UserInterface/Components/MeetingRoomCombo.cpp b/src/UserInterface/Components/MeetingRoomCombo.cpp
new file mode 100644 (file)
index 0000000..4b7a128
--- /dev/null
@@ -0,0 +1,106 @@
+#include "MeetingRoomCombo.h"
+
+#include <QComboBox>
+#include <QVBoxLayout>
+#include "Room.h"
+
+#include <QtDebug>
+
+MeetingRoomCombo::MeetingRoomCombo( QList<Room*> aRooms, QWidget *aParent ) :
+               ObservedWidget( aParent )
+{
+       iRooms = aRooms;
+       qSort( iRooms.begin(), iRooms.end(), Room::caseInsensitiveLessThan );
+
+       QFont regularTextFont;
+       regularTextFont.setBold( false );
+       regularTextFont.setPointSize( 12 );
+
+       iRoomCombo = new QComboBox( this );
+       for ( int i = 0; i < iRooms.count(); i++ )
+       {
+               iRoomCombo->addItem( iRooms.at( i )->name() );
+       }
+       iRoomCombo->setFont( regularTextFont );
+       connect( iRoomCombo, SIGNAL( currentIndexChanged( int ) ), this, SLOT( setCurrentIndex( int ) ) );
+       connect( iRoomCombo, SIGNAL( currentIndexChanged( const QString & ) ), this, SLOT( setCurrentRoomBy( const QString & ) ) );
+
+       QHBoxLayout *layout = new QHBoxLayout;
+       layout->addWidget( iRoomCombo );
+       layout->setMargin( 0 );
+       setLayout( layout );
+}
+
+MeetingRoomCombo::~MeetingRoomCombo()
+{
+       delete iRoomCombo;
+       iRooms.clear();
+}
+
+int MeetingRoomCombo::count()
+{
+       return iRoomCombo->count();
+}
+
+int MeetingRoomCombo::currentIndex()
+{
+       return iRoomCombo->currentIndex();
+}
+
+Room* MeetingRoomCombo::currentRoom()
+{
+       return currentIndex() >= 0 ? iRooms.at( currentIndex() ) : 0;
+}
+
+void MeetingRoomCombo::setCurrentIndex( int aIndex )
+{
+       if ( 0 <= aIndex && aIndex < count() )
+       {
+               iRoomCombo->setCurrentIndex( aIndex );
+       }
+       else
+       {
+               iRoomCombo->setCurrentIndex( -1 );
+       }
+
+       emit currentRoomChanged( currentRoom() );
+       emit currentIndexChanged( currentIndex() );
+}
+
+void MeetingRoomCombo::setCurrentRoom( Room *aRoom )
+{
+       setCurrentIndex( findRoom( aRoom ) );
+}
+
+void MeetingRoomCombo::setCurrentRoomBy( const QString &aName )
+{
+       setCurrentIndex( findRoomBy( aName ) );
+}
+
+int MeetingRoomCombo::findRoom( Room *aRoom )
+{
+       if ( aRoom == 0 )
+       {
+               qDebug() << "MeetingRoomCombo::findRoom\t-1";
+               return -1;
+       }
+
+       for ( int i = 0; i < iRooms.count(); i++ )
+       {
+               if ( aRoom->equals( *( iRooms.at( i ) ) ) )
+               {
+                       qDebug() << "MeetingRoomCombo::findRoom\t" << i;
+                       return i;
+               }
+       }
+       qDebug() << "MeetingRoomCombo::findRoom\t-1";
+       return -1;
+}
+
+int MeetingRoomCombo::findRoomBy( const QString &aName )
+{
+       return iRoomCombo->findText( aName );
+}
+
+
+
diff --git a/src/UserInterface/Components/MeetingRoomCombo.h b/src/UserInterface/Components/MeetingRoomCombo.h
new file mode 100644 (file)
index 0000000..5c7120a
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef MEETINGROOMCOMBO_H_\r
+#define MEETINGROOMCOMBO_H_\r
+\r
+#include "ObservedWidget.h"\r
+#include <QWidget>\r
+#include <QList>\r
+\r
+class QComboBox;\r
+class Room;\r
+\r
+//! Userinterface class. Displays a list of selectable meeting rooms.\r
+/*!\r
+ * Userinterface class. Displays a list of selectable meeting rooms. Customized QComboBox which hides\r
+ * all the not needed functionality of the "base" class.\r
+ */\r
+class MeetingRoomCombo : public ObservedWidget\r
+{\r
+       Q_OBJECT\r
+\r
+public:\r
+       //! Constructor.\r
+       /*!\r
+        * Constructs the MeetingRoomCombo.\r
+        * \param aRooms List of available rooms.\r
+        * \param aParent parent of the widget\r
+        */\r
+       MeetingRoomCombo( QList<Room*> aRooms, QWidget *aParent = 0 );\r
+       //! Destructor.\r
+       virtual ~MeetingRoomCombo();\r
+\r
+       //! Number of rooms.\r
+       /*!\r
+        * \return Number of rooms.\r
+        */\r
+       int count();\r
+       //! Current index\r
+       /*!\r
+        * \return Index of currently selected item.\r
+        */\r
+       int currentIndex();\r
+       //! Current room\r
+       /*!\r
+        * \return Pointer to the room currently selected.\r
+        */\r
+       Room* currentRoom();\r
+\r
+public slots:\r
+       //! Sets the current room\r
+       /*!\r
+        *  Sets the current room to match aIndex.\r
+        * \param aIndex index of item to be selected.\r
+        */\r
+       void setCurrentIndex( int aIndex );\r
+       //! Sets the current room\r
+       /*!\r
+        *  Sets the current room to be aRoom.\r
+        * \param aRoom Pointer to the room to be selected.\r
+        */\r
+       void setCurrentRoom( Room *aRoom );\r
+       //! Sets the current room\r
+       /*!\r
+        *  Sets the current room based on room's name.\r
+        * \param aName Name of the room to be selected.\r
+        */\r
+       void setCurrentRoomBy( const QString &aName );\r
+\r
+       //! Searches for the room.\r
+       /*!\r
+        *  Searches for the room "aRoom".\r
+        * \param aRoom Pointer to the room to be searched.\r
+        * \return Index of room if found. Otherwise negative.\r
+        */\r
+       int findRoom( Room *aRoom );\r
+       //! Searches for the room.\r
+       /*!\r
+        *  Searches for the room by its name.\r
+        * \param aName Name of the room to be searched.\r
+        * \return Index of room if found. Otherwise negative.\r
+        */\r
+       int findRoomBy( const QString &aName );\r
+\r
+signals:\r
+       //! Signals change of the current room.\r
+       /*!\r
+        *  Signal is emided when room is changed.\r
+        * \param aNewIndex Index of the item now selected.\r
+        */\r
+       void currentIndexChanged( int aNewIndex );\r
+       //! Signals change of the current room.\r
+       /*!\r
+        *  Signal is emided when room is changed.\r
+        * \param aNewRoom Pointer to the room now selected.\r
+        */\r
+       void currentRoomChanged( Room *aNewRoom );\r
+\r
+private:\r
+       //! Combobox containing the names of the rooms.\r
+       QComboBox *iRoomCombo;\r
+       //! List of rooms.\r
+       QList<Room*> iRooms;\r
+};\r
+\r
+#endif /*MEETINGROOMCOMBO_H_*/\r
diff --git a/src/UserInterface/Components/ObservedWidget.cpp b/src/UserInterface/Components/ObservedWidget.cpp
new file mode 100644 (file)
index 0000000..6dda69a
--- /dev/null
@@ -0,0 +1,61 @@
+#include "ObservedWidget.h"
+
+#include <QKeyEvent>
+#include <QTabletEvent>
+#include <QMouseEvent>
+#include <QMouseEvent>
+#include <QMouseEvent>
+
+#include <QtDebug>
+
+ObservedWidget::ObservedWidget( QWidget *aParent ) :
+               QWidget( aParent ),
+               iKeyEventsMonitored( true ),
+               iMouseEventsMonitored( true ),
+               iTabletEventsMonitored( true )
+{
+       setMouseTracking( true );
+
+       installEventFilter( this );
+}
+
+ObservedWidget::~ObservedWidget()
+{
+}
+
+void ObservedWidget::setKeyEventsMonitored( bool aIsMonitored )
+{
+       iKeyEventsMonitored = aIsMonitored;
+}
+
+void ObservedWidget::setMouseEventsMonitored( bool aIsMonitored )
+{
+       iMouseEventsMonitored = aIsMonitored;
+}
+
+void ObservedWidget::setTabletEventsMonitored( bool aIsMonitored )
+{
+       iTabletEventsMonitored = aIsMonitored;
+}
+
+bool ObservedWidget::eventFilter( QObject */*aWatched_object*/, QEvent *aEvent )
+{
+       switch ( aEvent->type() )
+       {
+               case( QEvent::KeyPress ) :
+               case( QEvent::TabletMove ) :
+               case( QEvent::TabletPress ) :
+//             case( QEvent::MouseMove ) :
+               case( QEvent::MouseButtonPress ) :
+               case( QEvent::MouseButtonDblClick ) :
+               {
+                       qDebug() << "ObservedWidget::eventFilter: " << aEvent;
+                       emit observedEventDetected();
+               }
+               default :
+               {
+                       break;
+               }
+       }
+       return false;
+}
diff --git a/src/UserInterface/Components/ObservedWidget.h b/src/UserInterface/Components/ObservedWidget.h
new file mode 100644 (file)
index 0000000..f07b919
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef OBSERVEDWIDGET_H_
+#define OBSERVEDWIDGET_H_
+
+#include <QWidget>
+
+class QKeyEvent;
+class QTabletEvent;
+class QMouseEvent;
+class QMouseEvent;
+class QMouseEvent;
+
+//! Userinterface class. Provides event monitoring.
+/*!
+ * UserInterface class. Provides event monitoring. The observed events are mouse, key and
+ * tablet events. They are used to detect user interadtion with the specified UI element.
+ */
+class ObservedWidget : public QWidget
+{
+       Q_OBJECT
+
+public:
+       //! Constructor.
+       /*!
+        * Constructor to initialize ObserverWidget instance.
+        * \param aParent The pointer to the parent widget. Optional.
+        */
+       ObservedWidget( QWidget *aParent = 0 );
+       //! Destructor.
+       virtual ~ObservedWidget();
+
+       //! Enables/disables monitoring of the key events.
+       /*!
+        * Enables/disables monitoring of the key events. Enables if the flag is true; otherwise, disables.
+        * \param aIsMonitored The flag.
+        */
+       void setKeyEventsMonitored( bool aIsMonitored );
+       //! Enables/disables monitoring of the mouse events.
+       /*!
+        * Enables/disables monitoring of the mouse events. Enables if the flag is true; otherwise, disables.
+        * \param aIsMonitored The flag.
+        */
+       void setMouseEventsMonitored( bool aIsMonitored );
+       //! Enables/disables monitoring of the tablet events.
+       /*!
+        * Enables/disables monitoring of the tablet events. Enables if the flag is true; otherwise, disables.
+        * \param aIsMonitored The flag.
+        */
+       void setTabletEventsMonitored( bool aIsMonitored );
+
+signals:
+       //! Signals if any of the monitored events is detected..
+       /*!
+        * Signal. Emitted if any of the monitored events is detected.
+        */
+       void observedEventDetected();
+
+protected:
+       //! Filters the detected events. ( TODO: improve event filtering!!! )
+       /*!
+        * Filters the detected events. If an event is being filtered, nothing else can see/detect it anymore,
+        * it is like if it did not even exist.
+        * \param aWatched_object The watched object.
+        * \param aEvent The event which is being filtered.
+        * \return True if the event was filtered; otherwise, false.
+        */
+       virtual bool eventFilter( QObject* aWatched_object, QEvent* aEvent );
+
+private:
+       bool iKeyEventsMonitored;
+       bool iMouseEventsMonitored;
+       bool iTabletEventsMonitored;
+
+};
+
+#endif /*OBSERVEDWIDGET_H_*/
diff --git a/src/UserInterface/Components/ScheduleWidget.cpp b/src/UserInterface/Components/ScheduleWidget.cpp
new file mode 100644 (file)
index 0000000..425a26f
--- /dev/null
@@ -0,0 +1,557 @@
+#include "ScheduleWidget.h"
+
+#include <QTableWidget>
+#include <QHeaderView>
+#include <QVBoxLayout>
+#include <QTime>
+#include <QtDebug>
+#include <QResizeEvent>
+#include <QPainter>
+#include "Meeting.h"
+
+const QColor ScheduleWidget::sFreeBackground = QColor( 192, 238, 189 );
+const QColor ScheduleWidget::sBusyBackground = QColor( 238, 147, 17 );
+const QColor ScheduleWidget::sHeaderBackground = QColor( Qt::white );
+const QColor ScheduleWidget::sDayHighlightColor = QColor( 255, 235, 160 );
+const QColor ScheduleWidget::sTimeHighlightColor = QColor( Qt::blue );
+const QColor ScheduleWidget::sMainGridColor = QColor( 140, 140, 140 );
+const QColor ScheduleWidget::sHalfGridColor = QColor( 195, 195, 195 );
+const QColor ScheduleWidget::sFrameColor = QColor( Qt::black );
+
+ScheduleTableWidget::ScheduleTableWidget( int aRows, int aColumns, QWidget *aParent ) :
+               QTableWidget( aRows, aColumns, aParent )
+{
+       ScheduleWidget* schedule = static_cast<ScheduleWidget*>( parent() );
+
+       iMeetingsByDay = new QList<MeetingContainer>[schedule->weekLengthAsDays()];
+       iTabletBlocked = false;
+       iTime.start();
+
+       setFocusPolicy( Qt::NoFocus );
+       setFrameStyle( QFrame::NoFrame );
+}
+
+ScheduleTableWidget::~ScheduleTableWidget()
+{
+       delete[] iMeetingsByDay;
+}
+
+void ScheduleTableWidget::paintEvent( QPaintEvent* aEvent )
+{
+       QTableWidget::paintEvent( aEvent );
+
+       ScheduleWidget* schedule = static_cast<ScheduleWidget*>( parent() );
+       QPainter painter( viewport() );
+       int rowHeight = rowViewportPosition( 2 ) - rowViewportPosition( 1 ) - 1;
+       int columnWidth = columnViewportPosition( 2 ) - columnViewportPosition( 1 ) - 1;
+
+       // draw frame around the table
+       QRect viewportRect = viewport()->rect();
+       viewportRect.adjust( 0, 0, -1, -1 );
+       painter.setPen( ScheduleWidget::sFrameColor );
+       painter.drawRect( viewportRect );
+
+       // draw horizontal half grid
+       for ( int i = 1; i < rowCount(); ++i )
+       {
+               int x = columnViewportPosition( 1 );
+               int y = rowViewportPosition( i ) + ( rowHeight / 2 ) - 1;
+               painter.fillRect( QRect( x, y, width() - x - 1, 1 ), ScheduleWidget::sHalfGridColor );
+       }
+
+       // draw horizontal main grid
+       for ( int i = 1; i < rowCount(); ++i )
+       {
+               int y = rowViewportPosition( i ) - 1;
+               painter.fillRect( QRect( 1, y, width() - 2, 1 ), ScheduleWidget::sMainGridColor );
+       }
+
+       // draw vertical main grid
+       for ( int i = 1; i < columnCount(); ++i )
+       {
+               int x = columnViewportPosition( i ) - 1;
+               painter.fillRect( QRect( x, 1, 1, height() - 2 ), ScheduleWidget::sMainGridColor );
+       }
+
+       // draw current day highlight
+       QPen pen( ScheduleWidget::sDayHighlightColor );
+       pen.setWidth( 3 );
+       painter.setPen( pen );
+       painter.setBrush( Qt::NoBrush );
+
+       for ( int i = 1; i < columnCount(); ++i )
+       {
+               if ( schedule->iCurrentDateTime.date() == schedule->iShownDate.addDays( i - 1 ) )
+               {
+                       int x = columnViewportPosition( i ) + 1;
+                       int y = 2;
+                       int w = columnWidth - 3;
+                       int h = height() - 5;
+                       painter.drawRect( x, y, w, h );
+                       break;
+               }
+       }
+
+       // draw meetings
+       QBrush brush( ScheduleWidget::sBusyBackground );
+       painter.setBrush( brush );
+       painter.setRenderHint( QPainter::Antialiasing );
+       painter.setPen( ScheduleWidget::sFrameColor );
+       populateMeetingList();
+
+       for ( int day = 0; day < schedule->weekLengthAsDays(); ++day )
+       {
+               for ( int i = 0; i < iMeetingsByDay[day].size(); ++i )
+               {
+                       painter.drawRoundRect( iMeetingsByDay[day][i].rect, 20, 20 );
+               }
+       }
+
+       // draw current time highlight
+       painter.setBrush( Qt::NoBrush );
+       painter.setRenderHint( QPainter::Antialiasing, false );
+
+       for ( int i = 1; i < columnCount(); ++i )
+       {
+               if ( schedule->iCurrentDateTime.date() == schedule->iShownDate.addDays( i - 1 ) )
+               {
+                       int x = columnViewportPosition( i ) - 1;
+                       int y = computeViewportY( schedule->iCurrentDateTime.time() );
+                       int w = columnWidth + 2;
+                       int h = 4;
+                       painter.fillRect( x, y, w, h, ScheduleWidget::sTimeHighlightColor );
+                       break;
+               }
+       }
+}
+
+void ScheduleTableWidget::tabletEvent( QTabletEvent* aEvent )
+{
+       int ms = iTime.restart();
+
+       if ( iTabletBlocked && ms > 1000 )
+       {
+               iTabletBlocked = false;
+               qDebug() << "Tablet block released";
+       }
+
+       if ( iTabletBlocked == false )
+       {
+               qDebug() << "Tablet blocked released";
+               activateMeeting( aEvent->x(), aEvent->y() );
+       }
+}
+
+void ScheduleTableWidget::mouseMoveEvent( QMouseEvent* /* aEvent */ )
+{
+       // this is overridden as empty method because otherwise
+       // unwanted behaviour would occur due to QTableWidget
+}
+
+void ScheduleTableWidget::mousePressEvent( QMouseEvent* aEvent )
+{
+       activateMeeting( aEvent->x(), aEvent->y() );
+}
+
+void ScheduleTableWidget::populateMeetingList()
+{
+       ScheduleWidget* schedule = static_cast<ScheduleWidget*>( parent() );
+
+       for ( int i = 0; i < schedule->weekLengthAsDays(); ++i )
+               iMeetingsByDay[i].clear();
+
+       // insert suitable meetings to list
+       for ( int i = 0; i < schedule->iMeetings.count(); ++i )
+       {
+               Meeting* meeting = schedule->iMeetings[i];
+               int day = meeting->startsAt().date().dayOfWeek() - 1;
+               if (( meeting->startsAt().date().weekNumber() == schedule->iShownDate.weekNumber() ) &&
+                         ( day < schedule->weekLengthAsDays() ) &&
+                         ( meeting->endsAt().time() > QTime( schedule->iStartHour, 0 ) ) &&
+                         ( meeting->startsAt().time() <= QTime( schedule->iStartHour + schedule->iNumberOfHours - 1,  59 ) ) )
+               {
+                       MeetingContainer container;
+                       container.meeting = meeting;
+                       container.rect = QRect( 0, 0, 0, 0 );
+                       container.rectComputed = false;
+                       iMeetingsByDay[day].append( container );
+               }
+       }
+
+       // compute meeting rectangles
+       for ( int day = 0; day < schedule->weekLengthAsDays(); ++day )
+       {
+               for ( int i = 0; i < iMeetingsByDay[day].size(); ++i )
+               {
+                       if ( iMeetingsByDay[day][i].rectComputed )
+                               continue;
+
+                       QList<int> meetingIndices;
+                       findOverlappingMeetings( day, iMeetingsByDay[day][i].meeting, meetingIndices );
+                       meetingIndices.append( i );
+
+                       for ( int j = 0; j < meetingIndices.size(); ++j )
+                       {
+                               if ( iMeetingsByDay[day][meetingIndices[j]].rectComputed )
+                                       continue;
+
+                               int columnWidth = columnViewportPosition( 2 ) - columnViewportPosition( 1 ) - 1;
+
+                               Meeting* meeting = iMeetingsByDay[day][meetingIndices[j]].meeting;
+                               int x = columnViewportPosition( day + 1 ) + ( int )(( columnWidth / ( float )meetingIndices.size() ) * j );
+                               int y = computeViewportY( meeting->startsAt().time() );
+                               int width = ( int )( columnWidth / ( float )meetingIndices.size() + 0.5f );
+                               int height = computeViewportY( meeting->endsAt().time() ) - y;
+
+                               iMeetingsByDay[day][meetingIndices[j]].rect = QRect( x, y, width, height );
+                               iMeetingsByDay[day][meetingIndices[j]].rectComputed = true;
+                       }
+               }
+       }
+}
+
+bool ScheduleTableWidget::findOverlappingMeetings( int aDay, Meeting* aMeeting, QList<int>& aResult )
+{
+       QSet<int> overlapSet;
+
+       // first find meetings that overlap with aMeeting
+       for ( int i = 0; i < iMeetingsByDay[aDay].size(); ++i )
+       {
+               Meeting* other = iMeetingsByDay[aDay][i].meeting;
+               if ( aMeeting != other && aMeeting->overlaps( *(other) ) )
+                       overlapSet.insert( i );
+       }
+
+       // then compare overlappiong ones against every meeting to make sure that
+       // the returned set can be used to compute rectangles for all cases at once
+       foreach( int index, overlapSet )
+       {
+               Meeting* meetingInSet = iMeetingsByDay[aDay][index].meeting;
+               for ( int i = 0; i < iMeetingsByDay[aDay].size(); ++i )
+               {
+                       Meeting* other = iMeetingsByDay[aDay][i].meeting;
+                       if ( meetingInSet != other && aMeeting != other && meetingInSet->overlaps( *(other) ) )
+                               overlapSet.insert( i );
+               }
+       }
+
+       aResult.clear();
+       foreach( int index, overlapSet )
+       {
+               aResult.append( index );
+       }
+
+       return !aResult.empty();
+}
+
+void ScheduleTableWidget::activateMeeting( int x, int y )
+{
+       ScheduleWidget* schedule = static_cast<ScheduleWidget*>( parent() );
+
+       for ( int day = 0; day < schedule->weekLengthAsDays(); ++day )
+       {
+               for ( int i = 0; i < iMeetingsByDay[day].size(); ++i )
+               {
+                       if ( iMeetingsByDay[day][i].rect.contains( x, y ) && !iTabletBlocked )
+                       {
+                               iTabletBlocked = true;
+                               qDebug() << "Activated meeting at x" << x << "y" << y << ":" << iMeetingsByDay[day][i].meeting->toString();
+                               emit schedule->meetingActivated( iMeetingsByDay[day][i].meeting );
+                       }
+               }
+       }
+}
+
+int ScheduleTableWidget::computeViewportY( QTime aTime )
+{
+       ScheduleWidget* schedule = static_cast<ScheduleWidget*>( parent() );
+       int secondsInDisplayDay = schedule->iNumberOfHours * 60 * 60;
+       int mainY = rowViewportPosition( 1 ) + 1;
+       int mainHeight = height() - mainY - 1;
+
+       return mainY + ( int )(( QTime( schedule->iStartHour, 0 ).secsTo( aTime ) / ( float )secondsInDisplayDay ) * mainHeight );
+}
+
+ScheduleWidget::ScheduleWidget( QDateTime aCurrentDateTime, DisplaySettings *aSettings, QWidget *aParent ) :
+               ObservedWidget( aParent ),
+               iCurrentDateTime( aCurrentDateTime ),
+               iStartHour( aSettings->dayStartsAt().hour() ),
+               iNumberOfHours( aSettings->dayEndsAt().hour() - aSettings->dayStartsAt().hour() + 1 ),
+               iDaysInSchedule( aSettings->daysInSchedule() ),
+               iLastRefresh( aCurrentDateTime.time() )
+{
+       iStartHour = qBound( 0, iStartHour, 23 );
+       iNumberOfHours = qBound( 1, iNumberOfHours, 24 - iStartHour );
+
+       iScheduleTable = new ScheduleTableWidget(( iNumberOfHours + 1 ) * 1, weekLengthAsDays() + 1, this );
+       iScheduleTable->horizontalHeader()->hide();
+       iScheduleTable->verticalHeader()->hide();
+       iScheduleTable->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
+       iScheduleTable->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
+       iScheduleTable->setShowGrid( false );
+
+       QFont font;
+       font.setPointSize( 10 );
+
+       // add empty item to top-left corner, this will be updated in refresh()
+       QTableWidgetItem *weekItem = new QTableWidgetItem();
+       weekItem->setTextAlignment( Qt::AlignCenter );
+       weekItem->setFlags( Qt::ItemIsEnabled );
+       weekItem->setBackgroundColor( sHeaderBackground );
+       weekItem->setFont( font );
+       iScheduleTable->setItem( 0, 0, weekItem );
+
+       // add empty item to main cell
+       QTableWidgetItem *mainItem = new QTableWidgetItem();
+       mainItem->setFlags( Qt::ItemIsEnabled );
+       mainItem->setBackgroundColor( sFreeBackground );
+       iScheduleTable->setItem( 1, 1, mainItem );
+
+       // set row header items
+       QTime time( iStartHour, 0 );
+       for ( int i = 1; i < iScheduleTable->rowCount(); ++i )
+       {
+               QTableWidgetItem *item = new QTableWidgetItem( time.toString( "HH:mm" ) );
+               item->setTextAlignment( Qt::AlignHCenter );
+               item->setFlags( Qt::ItemIsEnabled );
+               item->setBackgroundColor( sHeaderBackground );
+               item->setFont( font );
+               iScheduleTable->setItem( i, 0, item );
+               time = time.addSecs( 60 * 60 );
+       }
+
+       // set empty column header items, these will be updated in refresh()
+       for ( int i = 1; i < iScheduleTable->columnCount(); ++i )
+       {
+               QTableWidgetItem *item = new QTableWidgetItem();
+               item->setTextAlignment( Qt::AlignCenter );
+               item->setFlags( Qt::ItemIsEnabled );
+               item->setBackgroundColor( sHeaderBackground );
+               item->setFont( font );
+               iScheduleTable->setItem( 0, i, item );
+       }
+
+       QVBoxLayout *layout = new QVBoxLayout;
+       layout->addWidget( iScheduleTable );
+       layout->setAlignment( Qt::AlignCenter );
+       layout->setMargin( 0 );
+       setLayout( layout );
+
+       showCurrentWeek();
+}
+
+ScheduleWidget::~ScheduleWidget()
+{
+       clear();
+       delete iScheduleTable;
+}
+
+int    ScheduleWidget::shownWeek()
+{
+       return iShownDate.weekNumber();
+}
+
+QDate ScheduleWidget::beginningOfShownWeek()
+{
+       return iShownDate.addDays( -1 * iShownDate.dayOfWeek() + 1 );
+}
+
+Meeting* ScheduleWidget::currentMeeting()
+{
+       return meeting( iCurrentDateTime );
+}
+
+Meeting* ScheduleWidget::meeting( QDateTime aAt )
+{
+       for ( int i = 0; i < iMeetings.count(); ++i )
+       {
+               if ( iMeetings[i]->startsAt() <= aAt && iMeetings[i]->endsAt() >= aAt )
+               {
+                       return iMeetings[i];
+               }
+       }
+
+       return 0;
+}
+
+void ScheduleWidget::clear()
+{
+       qDebug() << "ScheduleWidget::clear";
+       int i = 0;
+       while ( !iMeetings.isEmpty() )
+       {
+               i++;
+               iMeetings.removeFirst();
+       }
+       qDebug() << "Deleted " << i << " items";
+}
+
+void ScheduleWidget::clear( QDateTime aFrom, QDateTime aUntil )
+{
+       for ( int i = 0; i < iMeetings.count(); ++i )
+       {
+               if (( iMeetings[i]->startsAt() >= aFrom && iMeetings[i]->startsAt() <= aUntil ) ||
+                         ( iMeetings[i]->startsAt() <= aFrom && iMeetings[i]->endsAt() >= aFrom ) )
+               {
+                       iMeetings.removeAt( i );
+                       --i;
+               }
+       }
+}
+
+void ScheduleWidget::refresh()
+{
+       for ( int i = 0; i < iScheduleTable->columnCount(); ++i )
+       {
+               QTableWidgetItem* item = iScheduleTable->item( 0, i );
+               QFont font = item->font();
+               if ( i == 0 ) {
+                       item->setText( tr( "Wk %1" ).arg( iShownDate.weekNumber() ) );
+                       continue;
+               }
+               item->setText( iShownDate.addDays( i - 1 ).toString( tr( "ddd d MMM" ) ) );
+
+               if ( iCurrentDateTime.date() == iShownDate.addDays( i - 1 ) )
+               {
+                       // mark current day
+                       item->setBackgroundColor( sDayHighlightColor );
+                       font.setItalic( true );
+                       item->setFont( font );
+               }
+               else
+               {
+                       item->setBackgroundColor( sHeaderBackground );
+                       font.setItalic( false );
+                       item->setFont( font );
+               }
+       }
+
+       // force repaint of the main area
+       iScheduleTable->setSpan( 1, 1, iNumberOfHours, weekLengthAsDays() );
+
+       iLastRefresh = iCurrentDateTime.time();
+}
+
+void ScheduleWidget::setCurrentDateTime( QDateTime aCurrentDateTime )
+{
+       Meeting* previous = meeting( iCurrentDateTime );
+       Meeting* current = meeting( aCurrentDateTime );
+       iCurrentDateTime = aCurrentDateTime;
+
+       if ( iLastRefresh.secsTo( iCurrentDateTime.time() ) > sRefreshIntervalInSeconds )
+       {
+               // enough time has elapsed since last refresh
+               refresh();
+       }
+
+       if ( previous != current )
+       {
+               emit currentMeetingChanged( current );
+       }
+}
+
+void ScheduleWidget::insertMeeting( Meeting *aMeeting )
+{
+       Meeting* previous = meeting( iCurrentDateTime );
+       iMeetings.append( aMeeting );
+       Meeting* current = meeting( iCurrentDateTime );
+
+       qDebug() << "Inserted" << aMeeting->toString();
+
+       refresh();
+
+       if ( previous != current )
+       {
+               emit currentMeetingChanged( current );
+       }
+}
+
+void ScheduleWidget::removeMeeting( Meeting *aMeeting )
+{
+       Meeting* previous = meeting( iCurrentDateTime );
+
+       qDebug() << "Delete" << aMeeting->toString();
+       for ( int i = 0; i < iMeetings.count(); ++i )
+       {
+               if ( iMeetings[i]->equals( *(aMeeting) ) )
+               {
+                       iMeetings.removeAt( i );
+
+                       refresh();
+
+                       Meeting* current = meeting( iCurrentDateTime );
+                       if ( previous != current )
+                               emit currentMeetingChanged( current );
+
+                       return;
+               }
+       }
+}
+
+//void ScheduleWidget::updateMeeting( Meeting *aMeeting )
+//{
+//
+//}
+
+void ScheduleWidget::showPreviousWeek()
+{
+       iShownDate = iShownDate.addDays( -7 );
+       refresh();
+       emit shownWeekChanged( iShownDate );
+}
+
+void ScheduleWidget::showCurrentWeek()
+{
+       iShownDate = iCurrentDateTime.date();
+
+       // set weekday to monday
+       iShownDate = iShownDate.addDays( -( iShownDate.dayOfWeek() - 1 ) );
+
+       refresh();
+       emit shownWeekChanged( iShownDate );
+}
+
+void ScheduleWidget::showNextWeek()
+{
+       iShownDate = iShownDate.addDays( 7 );
+       refresh();
+       emit shownWeekChanged( iShownDate );
+}
+
+int ScheduleWidget::computeHeaderRow( QTime aTime )
+{
+       // map given time to correct header row in the schedule table
+       return aTime.hour() - ( iStartHour - 1 );
+}
+
+int ScheduleWidget::weekLengthAsDays()
+{
+       return ( iDaysInSchedule == DisplaySettings::WholeWeekInSchedule ) ? 7 : 5;
+}
+
+void ScheduleWidget::resizeEvent( QResizeEvent* /* aEvent */ )
+{
+       QRect rect = iScheduleTable->contentsRect();
+       int rowHeight = ( int )( rect.height() / ( float )iScheduleTable->rowCount() );
+       int headerRowHeight = rowHeight;
+       int columnWidth = ( int )( rect.width() / ( iScheduleTable->columnCount() - 0.5f ) );
+       int headerColumnWidth = columnWidth / 2;
+
+       iScheduleTable->setRowHeight( 0, headerRowHeight );
+       for ( int i = 1; i < iScheduleTable->rowCount(); ++i )
+       {
+               iScheduleTable->setRowHeight( i, rowHeight );
+       }
+
+       iScheduleTable->setColumnWidth( 0, headerColumnWidth );
+       for ( int i = 1; i < iScheduleTable->columnCount(); ++i )
+       {
+               iScheduleTable->setColumnWidth( i, columnWidth );
+       }
+
+       // resize table so that frame size matches exactly
+       int leftMargin = 0, topMargin = 0, rightMargin = 0, bottomMargin = 0;
+       iScheduleTable->getContentsMargins( &leftMargin, &topMargin, &rightMargin, &bottomMargin );
+       iScheduleTable->resize( columnWidth * iScheduleTable->columnCount() - headerColumnWidth + leftMargin + rightMargin,
+                                       rowHeight * iScheduleTable->rowCount() + topMargin + bottomMargin );
+}
diff --git a/src/UserInterface/Components/ScheduleWidget.h b/src/UserInterface/Components/ScheduleWidget.h
new file mode 100644 (file)
index 0000000..690d77b
--- /dev/null
@@ -0,0 +1,346 @@
+#ifndef SCHEDULEWIDGET_H_
+#define SCHEDULEWIDGET_H_
+
+#include "ObservedWidget.h"
+#include <QDateTime>
+#include <QList>
+#include "DisplaySettings.h"
+#include <QTableWidget>
+
+class QTableWidgetItem;
+class Meeting;
+
+//! UserInterface class. Customizes the QTableWidget class.
+/*!
+ * UserInterface class. inherites QTableWidget to draw a custom table.
+ */
+class ScheduleTableWidget : public QTableWidget
+{
+       Q_OBJECT
+
+       //! Container for a meeting.
+       struct MeetingContainer
+       {
+               Meeting* meeting;
+               QRect rect;
+               bool rectComputed;
+       };
+
+public:
+
+       //! Constructor.
+       /*!
+        * Constructor to initialize ScheduleTableWidget instance.
+        * \param aRows number of rows
+        * \param aColumns number of columns
+        * \param aParent parent widget
+        */
+       ScheduleTableWidget( int aRows, int aColumns, QWidget *aParent = 0 );
+
+       //! Destructor.
+       ~ScheduleTableWidget();
+
+protected:
+       //! Handles drawing of main table area.
+       /*!
+        * Handles drawing of main table area.
+        * \param aEvent event
+        */
+       void paintEvent( QPaintEvent* aEvent );
+
+       //! Forwards relevant information to activateMeeting().
+       /*!
+        * Forwards relevant information to activateMeeting().
+        * \param aEvent event.
+        */
+       void tabletEvent( QTabletEvent* aEvent );
+
+       //! Mouse move event.
+       /*!
+        * Implemented as empty method for preventing unwanted QTableWidget behavior.
+        * \param aEvent event.
+        */
+       void mouseMoveEvent( QMouseEvent* aEvent );
+
+       //! Forwards relevant information to activateMeeting().
+       /*!
+        * Forwards relevant information to activateMeeting().
+        * \param aEvent event.
+        */
+       void mousePressEvent( QMouseEvent* aEvent );
+
+       
+private:
+       //! Populates meeting list.
+       /*!
+        * Populates meeting list.
+        */
+       void populateMeetingList();
+
+       //! Finds overlapping meetings.
+       /*!
+        * Finds overlapping meetings.
+        * \param aDay day.
+        * \param aMeeting meeting to compare.
+        * \param aResult generated list of overlapping meetings, empty if none.
+        * \return true if overlapping meetings were found, otherwise false.
+        */
+       bool findOverlappingMeetings( int aDay, Meeting* aMeeting, QList<int>& aResult );
+
+       //! Activates a meeting.
+       /*!
+        * Activates a meeting.
+        * \param x x coordinate
+        * \param y y coordinate
+        */
+       void activateMeeting( int x, int y );
+
+       //! Computes y coordinate in viewport for a given time.
+       /*!
+        * Computes y coordinate in viewport for a given time.
+        * \param aTime time
+        * \return y coordinate
+        */
+       int computeViewportY( QTime aTime );
+
+private:
+
+       //! Array of list of meetings, for each day.
+       QList<MeetingContainer>* iMeetingsByDay;
+       
+       //! Timer for tablet event blocking
+       QTime iTime;
+       
+       //! Flag telling if tablet events are blocked
+       bool iTabletBlocked;
+};
+
+//! UserInterface class. Defines a custom weekly calendar on the screen. Used by thr WeeklyViewWidget.
+/*!
+ * UserInterface class. Defines a custom weekly calendar on the screen. Used by thr WeeklyViewWidget.
+ */
+class ScheduleWidget : public ObservedWidget
+{
+       Q_OBJECT
+
+       friend class ScheduleTableWidget;
+
+public:
+
+       //! Constructor.
+       /*!
+        * Constructor to initialize ScheduleWidget instance.
+        * \param aCurrentDateTime Current date and time.
+        * \param aSettings Display settings.
+        * \param aParent Parent widget.
+        */
+       ScheduleWidget( QDateTime aCurrentDateTime, DisplaySettings *aSettings, QWidget *aParent = 0 );
+
+       //! Destructor.
+       virtual ~ScheduleWidget();
+
+       //! Gets number of current week.
+       /*!
+        * Gets number of current week.
+        * \return Number of week.
+        */
+       int     currentWeek();
+
+       //! Gets number of shown week.
+       /*!
+        * Gets number of shown week.
+        * \return The week which is currently shown.
+        */
+       int     shownWeek();
+
+       //! Gets the first day of shown week.
+       /*!
+        * Gets the first day of shown week.
+        * \return First day of the shown week.
+        */
+       QDate beginningOfShownWeek();
+
+       //! Gets current meeting.
+       /*!
+        * Gets current meeting.
+        * \return current meeting, 0 if none.
+        */
+       Meeting* currentMeeting();
+
+       //! Gets meeting at a specified date and time.
+       /*!
+        * Gets meeting at a specified date and time.
+        * \param aAt Time when the meeting is.
+        * \return meeting At the given time, 0 if none.
+        */
+       Meeting* meeting( QDateTime aAt );
+
+signals:
+
+       //! Signal. Emitted if a meeting is activated.
+       /*!
+        * Signal. Emitted if a meeting is activated, i.e. the user clicks on a meeting rectangle.
+        * \param aMeeting Actived meeting.
+        */
+       void meetingActivated( Meeting *aMeeting );
+
+       //! Signal. Emitted when the current meeting changes to another.
+       /*!
+        * Signal. Emitted when the current meeting changes to another.
+        * \param aNewMeeting New meeting.
+        */
+       void currentMeetingChanged( Meeting *aNewMeeting );
+
+       //! Signal. Emitted if the shown week has been changed.
+       /*!
+        * Signal. Emitted if the shown week has been changed.
+        * \param aDate The first date of the shown week.
+        */
+       void shownWeekChanged( QDate aDate );
+
+public slots:
+
+       //! Slot. Clears all meetings.
+       /*!
+        * Slot. Clears all meetings.
+        */
+       void clear();
+
+       //! Slot. Clears meetings based on a range.
+       /*!
+        * Slot. Clears meetings based on a range.
+        * \param aFrom Date and time from which the meetings are cleared.
+        * \param aUntil Date and time until which the meetings are cleared.
+        */
+       void clear( QDateTime aFrom, QDateTime aUntil );
+
+       //! Slot. Refreshes display.
+       /*!
+        * Slot. Refreshes display.
+        */
+       void refresh();
+
+       //! Slot. Sets current date and time.
+       /*!
+        * Slot. Sets current date and time.
+        * \param aCurrentDateTime Current date and time.
+        */
+       void setCurrentDateTime( QDateTime aCurrentDateTime );
+
+       //! Slot. Inserts a meeting to the schedule.
+       /*!
+        * Slot. Inserts a meeting to the schedule.
+        * \param aMeeting Meeting to be inserted.
+        */
+       void insertMeeting( Meeting *aMeeting );
+
+       //! Slot. Removes a meeting from the schedule.
+       /*!
+        * Slot. Removes a meeting from the schedule.
+        * \param aMeeting Meeting to be removed.
+        */
+       void removeMeeting( Meeting *aMeeting );
+
+       //! Slot. Updates a meeting in the schedule. (TODO)
+       /*!
+        * Slot updates a meeting in the schedule.
+        * \param aMeeting Meeting was updated.
+        */
+       void updateMeeting( Meeting */*aMeeting*/ ) {};
+
+       //! Slot. Shows previous week.
+       /*!
+        * Slot. Shows previous week.
+        */
+       void showPreviousWeek();
+
+       //! Slot. Shows current week.
+       /*!
+        * Slot. Shows current week.
+        */
+       void showCurrentWeek();
+
+       //! Slot. Shows next week.
+       /*!
+        * Slot. Shows next week.
+        */
+       void showNextWeek();
+
+private:
+
+       //! Computes header row.
+       /*!
+        * Computes header row number in schedule table based on given time.
+        * \param aTime Time.
+        * \return header Row.
+        */
+       int computeHeaderRow( QTime aTime );
+
+       //! Gets week length as days.
+       /*!
+        * Gets week length as days.
+        * \return Lenght of the week in days.
+        */
+       int weekLengthAsDays();
+
+       //! Computes proper cell sizes for the schedule table.
+       /*!
+        * Computes proper cell sizes for the schedule table.
+        * \param aEvent Resize event.
+        */
+       void resizeEvent( QResizeEvent *aEvent );
+
+private:
+       //! Schedule table widget.
+       ScheduleTableWidget *iScheduleTable;
+
+       //! Current date and time.
+       QDateTime iCurrentDateTime;
+
+       //! Meetings.
+       QList<Meeting*> iMeetings; /*! Not owned */
+
+       //! Currently shown week.
+       QDate iShownDate;
+
+       //! Starting hour of the schedule.
+       int iStartHour;
+
+       //! Number of hours in the schedule.
+       int iNumberOfHours;
+
+       //! Variable indicates the length of the week.
+       DisplaySettings::DaysInSchedule iDaysInSchedule;
+
+       //! When refresh() was called previously
+       QTime iLastRefresh;
+
+       //! Color for a free cell.
+       static const QColor sFreeBackground;
+
+       //! Color for a busy cell.
+       static const QColor sBusyBackground;
+
+       //! Color for headers.
+       static const QColor sHeaderBackground;
+
+       //! Color for current day highlight.
+       static const QColor sDayHighlightColor;
+
+       //! Color for current time highlight.
+       static const QColor sTimeHighlightColor;
+
+       //! Color for main grid.
+       static const QColor sMainGridColor;
+
+       //! Color for half grid.
+       static const QColor sHalfGridColor;
+
+       //! Color for frame.
+       static const QColor sFrameColor;
+
+       //! Refresh interval.
+       static const int sRefreshIntervalInSeconds = 60;
+};
+
+#endif /*SCHEDULEWIDGET_H_*/
diff --git a/src/UserInterface/Components/TimeDisplayWidget.cpp b/src/UserInterface/Components/TimeDisplayWidget.cpp
new file mode 100644 (file)
index 0000000..8267ca0
--- /dev/null
@@ -0,0 +1,40 @@
+#include "TimeDisplayWidget.h"\r
+\r
+TimeDisplayWidget::TimeDisplayWidget( QTime aNow, QWidget *aParent ) :\r
+               ObservedWidget( aParent )\r
+\r
+{\r
+       iCurrentTime = aNow;\r
+\r
+//     if( aParent && aParent->isWidgetType() )\r
+//     {\r
+//             this->setBackgroundColor( aParent->palette().color( QPalette::Window ) );\r
+//             this->setForegroundColor( aParent->palette().color( QPalette::WindowText ) );\r
+//     }\r
+}\r
+\r
+TimeDisplayWidget::~TimeDisplayWidget()\r
+{\r
+}\r
+\r
+QTime TimeDisplayWidget::time()\r
+{\r
+       return iCurrentTime;\r
+}\r
+\r
+void TimeDisplayWidget::setBackgroundColor( QColor aColor )\r
+{\r
+       this->setBackgroundColor( aColor );\r
+}\r
+\r
+void TimeDisplayWidget::setForegroundColor( QColor aColor )\r
+{\r
+       this->setForegroundColor( aColor );\r
+}\r
+\r
+void TimeDisplayWidget::setTime( QTime aNow )\r
+{\r
+       iCurrentTime = aNow;\r
+\r
+       showTime();\r
+}\r
diff --git a/src/UserInterface/Components/TimeDisplayWidget.h b/src/UserInterface/Components/TimeDisplayWidget.h
new file mode 100644 (file)
index 0000000..a1bcfd4
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef TIMEDISPLAYWIDGET_H_\r
+#define TIMEDISPLAYWIDGET_H_\r
+\r
+#include "ObservedWidget.h"\r
+#include <QWidget>\r
+#include <QColor>\r
+#include <QTime>\r
+\r
+//! Abstact. UserInterface class. Displays time.\r
+/*!\r
+ * Abstact. UserInterface class. Offers  basic functionality to display time. Inherited by\r
+ * DigitalTimeDisplayWidget.\r
+ */\r
+class TimeDisplayWidget : public ObservedWidget\r
+{\r
+       Q_OBJECT\r
+\r
+public:\r
+       //! Constructor.\r
+       /*!\r
+        * Basic constructor of TimeDisplayWidget.\r
+        * \param aNow Current time\r
+        * \param aParent Parent widget\r
+        */\r
+       TimeDisplayWidget( QTime aNow, QWidget *aParent = 0 );\r
+       //! Destructor\r
+       virtual ~TimeDisplayWidget();\r
+\r
+       //! Returns the current time\r
+       /*!\r
+        * \return Current time stored be the widget\r
+        */\r
+       QTime time();\r
+\r
+       //! Set background color\r
+       /*!\r
+        * \param aColor Color of widget backgroud\r
+        */\r
+       void setBackgroundColor( QColor aColor );\r
+       //! Set foreground color\r
+       /*!\r
+        * \param aColor Color of widget foregroud (text)\r
+        */\r
+       void setForegroundColor( QColor aColor );\r
+       //! Set frame visibility\r
+       /*!\r
+        * Pure virtual function to set the visibility of the frame\r
+        * \param aVisible True, if frame is drawn, otherwise false.\r
+        */\r
+       virtual void setFrameVisible( bool aVisible ) = 0;\r
+       //! Set size\r
+       /*!\r
+        * Pure virtual function to set the size of widget.\r
+        * \param aWidth\r
+        * \param aHeight\r
+        */\r
+       virtual void setSize( int aWidth, int aHeight ) = 0;\r
+       //! Set Font\r
+       /*!\r
+        * Pure virtual function to set the font.\r
+        * \param aFont\r
+        */\r
+       virtual void setFont( const QFont &aFont ) = 0;\r
+\r
+public slots:\r
+       //! Set time.\r
+       /*!\r
+        * Updates the time displayd.\r
+        * \param aNow Current time.\r
+        */\r
+       void setTime( QTime aNow );\r
+\r
+protected:\r
+       //! Displays the time.\r
+       /*!\r
+        * Pure virtual function to display time.\r
+        */\r
+       virtual void showTime() = 0;\r
+\r
+private:\r
+       //! Stores the time.\r
+       QTime iCurrentTime;\r
+\r
+};\r
+\r
+#endif /*TIMEDISPLAYWIDGET_H_*/\r
diff --git a/src/UserInterface/Utils/PasswordDialog.cpp b/src/UserInterface/Utils/PasswordDialog.cpp
new file mode 100644 (file)
index 0000000..332b0b6
--- /dev/null
@@ -0,0 +1,112 @@
+#include "PasswordDialog.h"
+#include <QLineEdit>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QByteArray>
+#include <QCryptographicHash>
+#include <QtDebug>
+#include <QLabel>
+
+PasswordDialog::PasswordDialog( QWidget *aParent, const QString &aPassword, const QString &aText, const QString &aTitle ) :
+               QDialog( aParent )
+{
+       setWindowTitle( aTitle.isNull() ? tr( "Enter password" ) : aTitle );
+       setModal( true );
+
+       // Store the password hash to iPasswordHash
+       // ( aPassword should be allready encoded )
+//     QCryptographicHash *hash = new QCryptographicHash( QCryptographicHash::Md5 );
+//     hash->addData( aPassword.toUtf8() );
+//     iPasswordHash = hash->result();
+//     delete hash;
+       iPasswordHash = aPassword.toUtf8();
+
+       /* Create the layout:
+
+       .--------title---------.
+       | text                 |
+       |                      |
+       | [***_______________] |
+       | [Cancel]      [ OK ] |
+       '----------------------'
+       */
+
+       QVBoxLayout *layout = new QVBoxLayout;
+
+       if ( !aText.isNull() )
+       {
+               QLabel *text = new QLabel( aText );
+               layout->addWidget( text );
+               layout->addStretch();
+       }
+
+       iPasswordEdit = new QLineEdit;
+       iPasswordEdit->setEchoMode( QLineEdit::Password );
+       layout->addWidget( iPasswordEdit );
+
+       QHBoxLayout *buttonLayout = new QHBoxLayout;
+       QPushButton *buttonOK = new QPushButton( tr( "OK" ) );
+       QPushButton *buttonCancel = new QPushButton( tr( "Cancel" ) );
+       
+       buttonLayout->addStretch();
+       buttonLayout->addWidget( buttonOK );
+       buttonLayout->addWidget( buttonCancel );
+       buttonLayout->addStretch();
+       layout->addSpacing( 5 );
+       layout->addLayout( buttonLayout );
+
+       // Connect the buttons pressed signals to corresponding slots
+       connect( buttonOK, SIGNAL( pressed() ), this, SLOT( okButtonPressed() ) );
+       connect( buttonCancel, SIGNAL( pressed() ), this, SLOT( cancelButtonPressed() ) );
+
+       // Enable the layout
+       setLayout( layout );
+}
+
+PasswordDialog::~PasswordDialog()
+{
+}
+
+void PasswordDialog::okButtonPressed()
+{
+       qDebug() << "PasswordDialog::okButtonPressed()";
+
+       // Get md5 hash from the password entered to the dialog
+       QCryptographicHash *hash = new QCryptographicHash( QCryptographicHash::Md5 );
+       hash->addData( iPasswordEdit->text().toUtf8() );
+       QByteArray userpw = hash->result();
+       delete hash; 
+       
+       // Compare the password hashes and emit corresponding signal tellin if the password was correct
+       if ( iPasswordHash == userpw.toHex() )
+       {
+               emit passwordEntered( PasswordDialog::Correct );
+               qDebug() << "Password OK";
+       }
+       else
+       {
+               emit passwordEntered( PasswordDialog::Incorrect );
+               qDebug() << "Incorrect password!";
+       }
+
+       // Close the dialog
+       close();
+}
+
+void PasswordDialog::cancelButtonPressed()
+{
+       qDebug() << "PasswordDialog::cancelButtonPressed()";
+
+       emit passwordEntered( PasswordDialog::Canceled );
+
+       close();
+}
+
+PasswordDialog * PasswordDialog::query( QWidget *aParent, const QString &aPassword, const QString &aText, const QString &aTitle )
+{
+       // Create a PasswordDialog instance and show it
+       PasswordDialog* dlg = new PasswordDialog( aParent, aPassword, aText, aTitle );
+       dlg->show();
+       return dlg;
+}
+
diff --git a/src/UserInterface/Utils/PasswordDialog.h b/src/UserInterface/Utils/PasswordDialog.h
new file mode 100644 (file)
index 0000000..5bf8c62
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef PASSWORDDIALOG_H_
+#define PASSWORDDIALOG_H_
+
+#include <QDialog>
+
+class QLineEdit;
+class QByteArray;
+
+//! UserInterface class. Responsible for poping-up password query on the screen.
+/*!
+ * UserInterface class. Responsible for poping-up password query on the screen. The class is used
+ * through static method, just like the QMessageBox in the standard Qt library.
+ */
+class PasswordDialog : public QDialog
+{
+       Q_OBJECT
+
+public:
+       //! Enumeration of password authenticity.
+       /*!
+        * Password authenticity.
+        */
+       enum PasswordStatus
+       {
+               Correct, /*!< Correct password. */
+               Incorrect, /*!< Incorrect password. */
+               Canceled
+       };
+
+       //! Creates a new PasswordDialog instance and shows the dialog on the screen.
+       /*!
+        * Creates a new Password query dialog.
+        * \param aParent The parent object.
+        * \param aPassword The password.
+        * \param aText Optional. Text displayed in the dialog.
+        * \param aTitle Optional. Dialog title, defaults to "Enter password".
+        * \return The instance which was created.
+        */
+       static PasswordDialog * query( QWidget *aParent, const QString &aPassword,
+                                                const QString &aText = 0, const QString &aTitle = 0 );
+
+signals:
+       //! Signals the authenticity of the password when the uuser dismisses the dialog.
+       /*!
+        * The signal is emitted if user presses a key available for the dialog.
+        * \param aStatus Password authenticity.
+        */
+       void passwordEntered( PasswordDialog::PasswordStatus aStatus );
+
+private slots:
+       void okButtonPressed();
+       void cancelButtonPressed();
+
+private:
+       //! Constructor.
+       /*!
+        * Constructor to initialize a PasswordDialog instance.
+        * \param aParent The parent object.
+        * \param aPassword The password.
+        */
+       PasswordDialog( QWidget *aParent, const QString &aPassword, const QString &aText, const QString &aTitle );
+       //! Destructor.
+       virtual ~PasswordDialog();
+
+       QLineEdit *iPasswordEdit;
+       QByteArray iPasswordHash;
+};
+
+#endif /*PASSWORDDIALOG_H_*/
diff --git a/src/UserInterface/Utils/PopUpMessageBox.cpp b/src/UserInterface/Utils/PopUpMessageBox.cpp
new file mode 100644 (file)
index 0000000..2738068
--- /dev/null
@@ -0,0 +1,196 @@
+#include "PopUpMessageBox.h"\r
+#include <QLabel>\r
+#include <QPushButton>\r
+#include <QVBoxLayout>\r
+#include <QTimer>\r
+#include <QImage>\r
+#include <QApplication>\r
+\r
+PopUpMessageBox::PopUpMessageBox( QWidget *aParent, const QString &aTitle, const QString &aText, Button aButton ) :\r
+               QDialog( aParent )\r
+{\r
+       setWindowTitle( aTitle );\r
+       setModal( true );\r
+\r
+       iIconLabel = new QLabel;\r
+       iIconLabel->setBackgroundRole( QPalette::HighlightedText );\r
+       iIconLabel->setMaximumSize( PopUpMessageBox::sIconSize, PopUpMessageBox::sIconSize );\r
+       //iIconLabel->setScaledContents( true );\r
+\r
+       iMessageLabel = new QLabel;\r
+       iMessageLabel->setWordWrap( true );\r
+       setMessage( aText );\r
+\r
+       QHBoxLayout *topLayout = new QHBoxLayout;\r
+       topLayout->addWidget( iIconLabel );\r
+       topLayout->addSpacing( 5 );\r
+       topLayout->addWidget( iMessageLabel, 10 );\r
+\r
+       QVBoxLayout *layout = new QVBoxLayout;\r
+       layout->addLayout( topLayout );\r
+\r
+       iButton = aButton;\r
+       switch ( iButton )\r
+       {\r
+               case OkButton:\r
+               {\r
+                       QPushButton *okButton = new QPushButton;\r
+                       okButton->setText( tr( "OK" ) );\r
+                       connect( okButton, SIGNAL( pressed() ), this, SLOT( okButtonPressed() ) );\r
+\r
+                       QHBoxLayout *buttonLayout = new QHBoxLayout;\r
+                       buttonLayout->addStretch();\r
+                       buttonLayout->addWidget( okButton );\r
+                       buttonLayout->addStretch();\r
+                       layout->addSpacing( 5 );\r
+                       layout->addLayout( buttonLayout );\r
+                       break;\r
+               }\r
+               case YesNoButton:\r
+               {\r
+                       QPushButton *yesButton = new QPushButton;\r
+                       yesButton->setText( tr( "Yes" ) );\r
+                       connect( yesButton, SIGNAL( pressed() ), this, SLOT( yesButtonPressed() ) );\r
+\r
+                       QPushButton *noButton = new QPushButton;\r
+                       noButton->setText( tr( "No" ) );\r
+                       connect( noButton, SIGNAL( pressed() ), this, SLOT( noButtonPressed() ) );\r
+\r
+                       QHBoxLayout *buttonLayout = new QHBoxLayout;\r
+                       buttonLayout->addStretch();\r
+                       buttonLayout->addWidget( yesButton );\r
+                       buttonLayout->addWidget( noButton );\r
+                       buttonLayout->addStretch();\r
+                       layout->addSpacing( 5 );\r
+                       layout->addLayout( buttonLayout );\r
+               }\r
+               default: // NoButtonAtAll\r
+               {\r
+                       iTimer = new QTimer;\r
+                       setInterval( PopUpMessageBox::DefaultInterval );\r
+                       connect( iTimer, SIGNAL( timeout() ), this, SLOT( close() ) );\r
+                       break;\r
+               }\r
+       }\r
+\r
+       setLayout( layout );\r
+}\r
+\r
+PopUpMessageBox::~PopUpMessageBox()\r
+{\r
+}\r
+\r
+QString PopUpMessageBox::getTitle()\r
+{\r
+       return windowTitle();\r
+}\r
+\r
+QString PopUpMessageBox::getMessage()\r
+{\r
+       return iMessageLabel->text();\r
+}\r
+\r
+bool PopUpMessageBox::setIcon( const QString &aPath )\r
+{\r
+       iIconLabel->clear();\r
+       QImage image( aPath );\r
+       if ( image.isNull() )\r
+       {\r
+               return false;\r
+       }\r
+       iIconLabel->setPixmap( QPixmap::fromImage( image ) );\r
+       return true;\r
+}\r
+\r
+void PopUpMessageBox::setTitle( const QString &aTitle )\r
+{\r
+       setWindowTitle( aTitle );\r
+}\r
+\r
+void PopUpMessageBox::setMessage( const QString &aMsg )\r
+{\r
+       iMessageLabel->setText( aMsg );\r
+}\r
+\r
+void PopUpMessageBox::setInterval( int aInternal )\r
+{\r
+       iTimer->setInterval( aInternal );\r
+}\r
+\r
+void PopUpMessageBox::popUp()\r
+{\r
+       show();\r
+       if ( iButton == NoButtonAtAll )\r
+       {\r
+               iTimer->start();\r
+       }\r
+}\r
+\r
+void PopUpMessageBox::yesButtonPressed()\r
+{\r
+       emit buttonPressed( PopUpMessageBox::YesReturnType );\r
+       close();\r
+}\r
+\r
+void PopUpMessageBox::noButtonPressed()\r
+{\r
+       emit buttonPressed( PopUpMessageBox::NoReturnType );\r
+       close();\r
+}\r
+\r
+void PopUpMessageBox::okButtonPressed()\r
+{\r
+       emit buttonPressed( PopUpMessageBox::OkReturnType );\r
+       close();\r
+}\r
+\r
+PopUpMessageBox * PopUpMessageBox::cancel( QWidget *aParent, const QString &aText )\r
+{\r
+       PopUpMessageBox* msg = new PopUpMessageBox( aParent, tr( "Cancel" ), aText, NoButtonAtAll );\r
+       msg->setIcon( ":/popup_cancel" );\r
+       msg->popUp();\r
+       QApplication::beep();\r
+       return msg;\r
+}\r
+\r
+PopUpMessageBox * PopUpMessageBox::error( QWidget *aParent, const QString &aText )\r
+{\r
+       PopUpMessageBox* msg = new PopUpMessageBox( aParent, tr( "Error" ), aText, NoButtonAtAll );\r
+       msg->setIcon( ":/popup_error" );\r
+       msg->popUp();\r
+       QApplication::beep();\r
+       return msg;\r
+}\r
+\r
+PopUpMessageBox * PopUpMessageBox::information( QWidget *aParent, const QString &aText )\r
+{\r
+       PopUpMessageBox* msg = new PopUpMessageBox( aParent, tr( "Information" ), aText, NoButtonAtAll );\r
+       msg->setIcon( ":/popup_information" );\r
+       msg->popUp();\r
+       return msg;\r
+}\r
+\r
+PopUpMessageBox * PopUpMessageBox::ok( QWidget *aParent, const QString &aText )\r
+{\r
+       PopUpMessageBox* msg = new PopUpMessageBox( aParent, tr( "OK" ), aText, OkButton );\r
+       msg->setIcon( ":/popup_ok" );\r
+       msg->popUp();\r
+       return msg;\r
+}\r
+\r
+PopUpMessageBox * PopUpMessageBox::warning( QWidget *aParent, const QString &aText )\r
+{\r
+       PopUpMessageBox* msg = new PopUpMessageBox( aParent, tr( "Warning" ), aText, NoButtonAtAll );\r
+       msg->setIcon( ":/popup_warning" );\r
+       msg->popUp();\r
+       QApplication::beep();\r
+       return msg;\r
+}\r
+\r
+PopUpMessageBox * PopUpMessageBox::question( QWidget *aParent, const QString &aText )\r
+{\r
+       PopUpMessageBox* msg = new PopUpMessageBox( aParent, tr( "Question" ), aText, YesNoButton );\r
+       msg->setIcon( ":/popup_question" );\r
+       msg->popUp();\r
+       return msg;\r
+}\r
diff --git a/src/UserInterface/Utils/PopUpMessageBox.h b/src/UserInterface/Utils/PopUpMessageBox.h
new file mode 100644 (file)
index 0000000..ac7670f
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef POPUPMESSAGEBOX_H_\r
+#define POPUPMESSAGEBOX_H_\r
+\r
+#include <QDialog>\r
+\r
+class QLabel;\r
+\r
+//! UserInterface class. Responsible for poping-up information messages on the screen.\r
+/*!\r
+ * UserInterface class. Responsible for poping-up information messages on the screen. The class is used\r
+ * through static methods, just like the QMessageBox in the standard Qt library.\r
+ */\r
+class PopUpMessageBox : public QDialog\r
+{\r
+       Q_OBJECT\r
+\r
+public:\r
+       //! Enumeration of dialog buttons.\r
+       /*!\r
+        * Predefined buttons for the pop up dialogs.\r
+        */\r
+       enum Button\r
+       {\r
+               NoButtonAtAll, /*!< There is no button. Dialog pops up for the specified interval, then automatically closes. */\r
+               OkButton, /*!< OK button on the right. */\r
+               YesNoButton /*!< Yes and No buttons. */\r
+       };\r
+       //! Enumeration of possible return types after the specified Key was pressed.\r
+       /*!\r
+        * Predefined return types after the specified Key was pressed.\r
+        * \sa PopUpMessageBox::Key.\r
+        */\r
+       enum ReturnType\r
+       {\r
+               YesReturnType, /*!< Yes was pressed. */\r
+               NoReturnType, /*!< No was pressed. */\r
+               OkReturnType /*!< OK was pressed. */\r
+       };\r
+\r
+signals:\r
+       //! Signals if user presses a key available for the dialog.\r
+       /*!\r
+        * The signal is emitted if user presses a key available for the dialog.\r
+        * \param aReturnType The return type based on the key.\r
+        * \sa PopUpMessageBox::ReturnType.\r
+        */\r
+       void buttonPressed( PopUpMessageBox::ReturnType aReturnType );\r
+\r
+private slots:\r
+       void yesButtonPressed();\r
+       void noButtonPressed();\r
+       void okButtonPressed();\r
+\r
+private:\r
+       //! Constructor.\r
+       /*!\r
+        * Constructor to initialize a PopUpMessageBox instance.\r
+        * \param aParent Optional. The parent object.\r
+        * \param aTitle Optional. The title of the dialog.\r
+        * \param aText Optional. The message the dialog supposed to show.\r
+        * \param aKey Optional. The keys which are accessible when the dialog is active. There is no key by default.\r
+        * \sa PopUpMessage::Key.\r
+        */\r
+       PopUpMessageBox( QWidget *aParent = 0, const QString &aTitle = 0, const QString &aText = 0, Button aButton = NoButtonAtAll );\r
+       //! Destructor.\r
+       virtual ~PopUpMessageBox();\r
+\r
+       //! Gets the title.\r
+       /*!\r
+        * Getter method to provide the title attribute of the object.\r
+        * \return The title as a QString.\r
+        */\r
+       QString getTitle();\r
+       //! Gets the message text.\r
+       /*!\r
+        * Getter method to provide the message text of the dialog.\r
+        * \return The message as a QString.\r
+        */\r
+       QString getMessage();\r
+       //! Sets the icon for the dialog.\r
+       /*!\r
+        * Sets the icon for the dialog.\r
+        * \param aPath The full path of the icon.\r
+        * \return TRUE if setting of icon was successful; otherwise, FALSE.\r
+        */\r
+       bool setIcon( const QString &aPath );\r
+       //! Sets the title.\r
+       /*!\r
+        * Sets the title of the current object.\r
+        * \param aTitle The new title.\r
+        */\r
+       void setTitle( const QString &aTitle );\r
+       //! Sets the message text.\r
+       /*!\r
+        * Sets the message text of the current object.\r
+        * \param aText The new text.\r
+        */\r
+       void setMessage( const QString &aText );\r
+       //! Sets the interval of being popped up.\r
+       /*!\r
+        * Sets the interval of the current object until when it is popped up.\r
+        * \param aInterval The new interval.\r
+        */\r
+       void setInterval( int aInterval );\r
+       //! Pops the dialog up.\r
+       /*!\r
+        * Pops the dialog up for the specified time interval if no key is specified; otherwise, until there is\r
+        * a key (actually softkey button) pressed.\r
+        * \sa PopUpMessageBox::Key.\r
+        */\r
+       void popUp();\r
+\r
+public:\r
+       //! Creates a new PopUpMessageBox instance.\r
+       /*!\r
+        * Creates a new 'Cancel' PopUpMessage instance without buttons.\r
+        * \param aParent The parent object.\r
+        * \param aText Optional. The message text.\r
+        * \return The instance which was created.\r
+        * \sa popUp().\r
+        */\r
+       static PopUpMessageBox * cancel( QWidget *aParent, const QString &aText = 0 );\r
+       //! Creates a new PopUpMessageBox instance.\r
+       /*!\r
+        * Creates a new 'Error' PopUpMessage instance without buttons.\r
+        * \param aParent The parent object.\r
+        * \param aText Optional. The message text.\r
+        * \return The instance which was created.\r
+        * \sa popUp().\r
+        */\r
+       static PopUpMessageBox * error( QWidget *aParent, const QString &aText = 0 );\r
+       //! Creates a new PopUpMessageBox instance.\r
+       /*!\r
+        * Creates a new 'Information' PopUpMessage instance without buttons.\r
+        * \param aParent The parent object.\r
+        * \param aText Optional. The message text.\r
+        * \return The instance which was created.\r
+        * \sa popUp().\r
+        */\r
+       static PopUpMessageBox * information( QWidget *aParent, const QString &aText = 0 );\r
+       //! Creates a new PopUpMessageBox instance.\r
+       /*!\r
+        * Creates a new 'OK' PopUpMessage instance without buttons.\r
+        * \param aParent The parent object.\r
+        * \param aText Optional. The message text.\r
+        * \return The instance which was created.\r
+        * \sa popUp().\r
+        */\r
+       static PopUpMessageBox * ok( QWidget *aParent, const QString &aText = 0 );\r
+       //! Creates a new PopUpMessageBox instance.\r
+       /*!\r
+        * Creates a new 'Question' PopUpMessage instance with 'Yes' and 'No' buttons.\r
+        * \param aParent The parent object.\r
+        * \param aText Optional. The message text.\r
+        * \return The instance which was created.\r
+        * \sa popUp().\r
+        */\r
+       static PopUpMessageBox * question( QWidget *aParent, const QString &aText = 0 );\r
+       //! Creates a new PopUpMessageBox instance.\r
+       /*!\r
+        * Creates a new 'Warning' PopUpMessage instance without buttons.\r
+        * \param aParent The parent object.\r
+        * \param aText Optional. The message text.\r
+        * \return The instance which was created.\r
+        * \sa popUp().\r
+        */\r
+       static PopUpMessageBox * warning( QWidget *aParent, const QString &aText = 0 );\r
+\r
+public:\r
+       //! The default pop-up interval in milliseconds.\r
+       static const int DefaultInterval = 2500; // ms\r
+\r
+private:\r
+       QLabel *iIconLabel;\r
+       QLabel *iMessageLabel;\r
+       QTimer *iTimer;\r
+       Button iButton;\r
+\r
+       static const int sIconSize = 25;\r
+\r
+};\r
+\r
+\r
+#endif /*POPUPMESSAGEBOX_H_*/\r
diff --git a/src/UserInterface/Utils/ToolBox.cpp b/src/UserInterface/Utils/ToolBox.cpp
new file mode 100644 (file)
index 0000000..ba3e146
--- /dev/null
@@ -0,0 +1,10 @@
+#include "ToolBox.h"
+
+#include <QLabel>
+
+QLabel* ToolBox::createLabel( const QString &aText, const QFont &aFont )
+{
+       QLabel *label = new QLabel( aText );
+       label->setFont( aFont );
+       return label;
+}
diff --git a/src/UserInterface/Utils/ToolBox.h b/src/UserInterface/Utils/ToolBox.h
new file mode 100644 (file)
index 0000000..2ed778a
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef TOOLBOX_H_
+#define TOOLBOX_H_
+
+#include <QFont>
+
+class QLabel;
+
+//! UserInterface class. Provides reusable functions for component creation.
+/*!
+ * UserInterface class. Provides reusable functions for component creation.
+ */
+class ToolBox
+{
+public:
+       //! Creates a label.
+       /*!
+        * Creates a label based on the specified text and font type.
+        * \param aText The text being shown in the label.
+        * \param aFont The font being used to specify the text.
+        */
+       static QLabel* createLabel( const QString &aText, const QFont &aFont );
+
+};
+
+#endif /*TOOLBOX_H_*/
diff --git a/src/UserInterface/Views/MeetingInfoDialog.cpp b/src/UserInterface/Views/MeetingInfoDialog.cpp
new file mode 100644 (file)
index 0000000..95e2cce
--- /dev/null
@@ -0,0 +1,85 @@
+#include "MeetingInfoDialog.h"
+#include "ToolBox.h"
+#include "Meeting.h"
+#include "Room.h"
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QPushButton>
+#include <QTextEdit>
+#include <QDebug>
+
+MeetingInfoDialog::MeetingInfoDialog( Meeting *aMeeting, QWidget *aParent ) :
+               QDialog( aParent )
+{
+       setWindowTitle( tr( "Details" ) );
+
+       QFont normalFont;
+       normalFont.setPointSize( 11 );
+
+       QFont boldFont;
+       boldFont.setPointSize( 11 );
+       boldFont.setBold( true );
+
+       QLabel *subjectLabel = ToolBox::createLabel( tr( "Subject:" ), boldFont );
+       QLabel *subjectContent = ToolBox::createLabel( aMeeting->subject(), normalFont );
+
+       QLabel *descriptionLabel = ToolBox::createLabel( tr( "Description:" ), boldFont );
+       QTextEdit *descriptionContent = new QTextEdit( "" );
+       descriptionContent->setHtml( aMeeting->description() );
+       descriptionContent->setReadOnly( true );
+       descriptionContent->setFont( normalFont );
+
+       QLabel *organizerLabel = NULL;
+       QLabel *organizerContent = NULL;
+       
+       QString roomAddr = aMeeting->room().address();
+       QString organizer = aMeeting->organizer();
+       if( !organizer.contains( roomAddr ) )
+       {
+               organizerLabel = ToolBox::createLabel( tr( "Organizer:" ), boldFont );
+               organizerContent = ToolBox::createLabel( aMeeting->organizer(), normalFont );
+       }
+       QLabel *startsAtLabel = ToolBox::createLabel( tr( "Starts at:" ), boldFont );
+       QLabel *startsAtContent = ToolBox::createLabel( aMeeting->startsAt().toString( tr( "d MMMM yyyy hh:mm" ) ), normalFont );
+
+       QLabel *endsAtLabel = ToolBox::createLabel( tr( "Ends at:" ), boldFont );
+       QLabel *endsAtContent = ToolBox::createLabel( aMeeting->endsAt().toString( tr( "d MMMM yyyy hh:mm" ) ), normalFont );
+
+       QPushButton *button = new QPushButton;
+       button->setText( tr( "OK" ) );
+       connect( button, SIGNAL( clicked() ), this, SLOT( close() ) );
+
+       QHBoxLayout *buttonLayout = new QHBoxLayout;
+       buttonLayout->addStretch();
+       buttonLayout->addWidget( button );
+       buttonLayout->addStretch();
+
+       QVBoxLayout *layout = new QVBoxLayout;
+       layout->addWidget( subjectLabel );
+       layout->addWidget( subjectContent );
+       layout->addSpacing( 5 );
+       layout->addWidget( descriptionLabel );
+       layout->addWidget( descriptionContent );
+       layout->addSpacing( 5 );
+       if( organizerLabel )
+               layout->addWidget( organizerLabel );
+       if( organizerContent )
+               layout->addWidget( organizerContent );
+       layout->addSpacing( 5 );
+       layout->addWidget( startsAtLabel );
+       layout->addWidget( startsAtContent );
+       layout->addSpacing( 5 );
+       layout->addWidget( endsAtLabel );
+       layout->addWidget( endsAtContent );
+       layout->addSpacing( 5 );
+       layout->addStretch();
+       layout->addLayout( buttonLayout );
+       setLayout( layout );
+
+       setMinimumWidth( MeetingInfoDialog::width );
+       setMinimumHeight( MeetingInfoDialog::height );
+}
+
+MeetingInfoDialog::~MeetingInfoDialog()
+{
+}
diff --git a/src/UserInterface/Views/MeetingInfoDialog.h b/src/UserInterface/Views/MeetingInfoDialog.h
new file mode 100644 (file)
index 0000000..a62cb32
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef MEETINGINFODIALOG_H_\r
+#define MEETINGINFODIALOG_H_\r
+\r
+#include <QDialog>\r
+\r
+class Meeting;\r
+class QLabel;\r
+\r
+//! UserInterface class. Provides detailed information about meetings in a dialog box.\r
+/*!\r
+ * UserInterface class. Provides detailed information about meetings in a dialog box.\r
+ */\r
+class MeetingInfoDialog : public QDialog\r
+{\r
+public:\r
+       //! Constructor.\r
+       /*!\r
+        * Constructor to initialize MeetingInfoDialog instances.\r
+        * \param aMeeting The Meeting instance which is needed to be presented in detail.\r
+        * \param aParent Pointer to the parent widget. Optional.\r
+        */\r
+       MeetingInfoDialog( Meeting *aMeeting, QWidget *aParent = 0 );\r
+       //! Destructor.\r
+       virtual ~MeetingInfoDialog();\r
+\r
+private:\r
+\r
+       static const int width = 200;\r
+       static const int height = 400;\r
+\r
+};\r
+\r
+#endif /*MEETINGINFODIALOG_H_*/\r
diff --git a/src/UserInterface/Views/RoomStatusIndicatorWidget.cpp b/src/UserInterface/Views/RoomStatusIndicatorWidget.cpp
new file mode 100644 (file)
index 0000000..7421a47
--- /dev/null
@@ -0,0 +1,120 @@
+#include "RoomStatusIndicatorWidget.h"\r
+\r
+#include <QLabel>\r
+#include <QFont>\r
+#include <QVBoxLayout>\r
+#include "DigitalTimeDisplayWidget.h"\r
+#include "ToolBox.h"\r
+\r
+#include <QtDebug>\r
+\r
+QTime RoomStatusIndicatorWidget::endOfTheDay = QTime( 23, 59, 0, 0 );\r
+\r
+RoomStatusIndicatorWidget::RoomStatusIndicatorWidget( Room *aDefaultRoom, Room::Status aStatus, QTime aUntil, QString aTimeFormat, QWidget *aParent ) :\r
+               ObservedWidget( aParent ), iTimeFormat( aTimeFormat )\r
+{\r
+       QFont importantTextFont;\r
+       //importantTextFont.setBold( true );\r
+       importantTextFont.setPointSize( 20 );\r
+\r
+       QFont regularTextFont;\r
+       //regularTextFont.setBold( true );\r
+       regularTextFont.setPointSize( 12 );\r
+\r
+       // display for current time\r
+       // Note: the time display receives current time info from Engine::clock()\r
+       iTimeDisplay = new DigitalTimeDisplayWidget( QTime::currentTime(), iTimeFormat, this );\r
+       iTimeDisplay->setFrameVisible( false );\r
+       iTimeDisplay->setSize( 250, 120 );\r
+\r
+       // Pegasus\r
+       iDefaultRoomLabel = ToolBox::createLabel( aDefaultRoom->name(), importantTextFont );\r
+       iDefaultRoomLabel->setAlignment( Qt::AlignHCenter );\r
+       iDefaultRoomLabel->setStyleSheet( "background-color: transparent" );\r
+       // is busy\r
+       iStatusLabel = ToolBox::createLabel( tr( "is %1" ).arg( statusToText( aStatus ) ), importantTextFont );\r
+       iStatusLabel->setAlignment( Qt::AlignHCenter );\r
+       iStatusLabel->setStyleSheet( "background-color: transparent" );\r
+\r
+       // until 13:22\r
+       iUntilTextLabel = ToolBox::createLabel( tr( "until %1" ).arg( aUntil.toString( iTimeFormat ) ), importantTextFont );\r
+       iUntilTextLabel->setAlignment( Qt::AlignHCenter );\r
+       iUntilTextLabel->setStyleSheet( "background-color: transparent" );\r
+\r
+       QVBoxLayout *topLayout = new QVBoxLayout;\r
+       topLayout->addStretch();\r
+       topLayout->addWidget( iTimeDisplay );\r
+       topLayout->addWidget( iDefaultRoomLabel );\r
+       topLayout->addWidget( iStatusLabel );\r
+       topLayout->addWidget( iUntilTextLabel );\r
+       topLayout->addStretch();\r
+\r
+       QHBoxLayout *mainLayout = new QHBoxLayout;\r
+       mainLayout->addLayout( topLayout );\r
+       mainLayout->addStretch();\r
+       mainLayout->setMargin( 65 );\r
+       setLayout( mainLayout );\r
+\r
+       statusChanged( aStatus, aUntil );\r
+\r
+       setFocusPolicy( Qt::StrongFocus );\r
+       setEnabled( true ); // enable mouse & key events\r
+}\r
+\r
+RoomStatusIndicatorWidget::~RoomStatusIndicatorWidget()\r
+{\r
+       delete iTimeDisplay;\r
+       iTimeDisplay = 0;\r
+}\r
+\r
+QString RoomStatusIndicatorWidget::statusToText( const Room::Status aStatus )\r
+{\r
+       return ( aStatus == Room::BusyStatus ) ? tr( "busy" ) : tr( "free" );\r
+}\r
+\r
+QPalette RoomStatusIndicatorWidget::createPalette( Room::Status aStatus )\r
+{\r
+       QPixmap pixmap( aStatus == Room::BusyStatus ? ":roomstatus_busy" : ":roomstatus_free" );\r
+\r
+       // The image needs to be moved in normal mode so the traffic light not partly outside the screen\r
+       const int xoffset( 60 );\r
+       const int yoffset( 19 );\r
+       int cropwidth( pixmap.width() - xoffset );\r
+       int cropheight( pixmap.height() - yoffset );\r
+       \r
+       QBrush brush;\r
+       if ( windowState() == Qt::WindowFullScreen )\r
+       {\r
+               // Use the full image in full screen mode\r
+               brush.setTexture( pixmap );\r
+       }\r
+       else\r
+       {\r
+               // Take part of the image so the traffic lights are moved xoffset poxels to left \r
+               // and yoffset pixels to up\r
+               brush.setTexture( pixmap.copy( xoffset, yoffset, cropwidth, cropheight ) );\r
+       }\r
+\r
+       QPalette palette;\r
+       palette.setBrush( QPalette::Window, brush );\r
+       return palette;\r
+}\r
+\r
+void RoomStatusIndicatorWidget::setCurrentTime( QTime aCurrentTime )\r
+{\r
+       iTimeDisplay->setTime( aCurrentTime );\r
+}\r
+\r
+void RoomStatusIndicatorWidget::statusChanged( const Room::Status aStatus, const QTime aUntil )\r
+{\r
+       iStatusLabel->setText( tr( "is %1" ).arg( statusToText( aStatus ) ) );\r
+       if ( aUntil == RoomStatusIndicatorWidget::endOfTheDay )\r
+       {\r
+               iUntilTextLabel->setText( tr( "whole day." ) );\r
+       }\r
+       else\r
+       {\r
+               iUntilTextLabel->setText( tr( "until %1" ).arg( aUntil.toString( iTimeFormat ) ) );\r
+       }\r
+       setPalette( createPalette( aStatus ) );\r
+}\r
diff --git a/src/UserInterface/Views/RoomStatusIndicatorWidget.h b/src/UserInterface/Views/RoomStatusIndicatorWidget.h
new file mode 100644 (file)
index 0000000..615051e
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef ROOMSTATUSINDICATORWIDGET_H_\r
+#define ROOMSTATUSINDICATORWIDGET_H_\r
+\r
+#include "ObservedWidget.h"\r
+#include <QTime>\r
+#include <QKeyEvent>\r
+#include <QTabletEvent>\r
+\r
+#include "Room.h"\r
+\r
+class QLabel;\r
+class QVBoxLayout;\r
+class TimeDisplayWidget;\r
+\r
+//! UserInterface class. Indicates if the default meeting room is busy or not.\r
+/*!\r
+ * UserInterface class. Indicates if the default meeting room is busy or not. This widget\r
+ * appears on the screen if there was no user interaction with the device for a ceratin period of time,\r
+ * and disappears if there is any. Its function is to behave like a screen saver on one hand, and\r
+ * to provide details about the current availability on the other hand.\r
+ */\r
+class RoomStatusIndicatorWidget : public ObservedWidget\r
+{\r
+       Q_OBJECT\r
+\r
+public:\r
+       //! Contructor.\r
+       /*!\r
+        * Constructor to initialize RoomStatusIndicatorWidget instances.\r
+        * \param aDefaultRoom The room which's status is indicated by the current instance.\r
+        * \param aStatus The current status of the room.\r
+        * \param aUntil Time until the availability information is valid.\r
+        * \param aTimeFormat Time format string.\r
+        * \param aParent Pointer to the parent widget. Optional.\r
+        *\r
+        */\r
+       RoomStatusIndicatorWidget( Room *aDefaultRoom, Room::Status aStatus, QTime aUntil, QString aTimeFormat, QWidget *aParent = 0 );\r
+       //! Destructor.\r
+       virtual ~RoomStatusIndicatorWidget();\r
+\r
+public slots:\r
+       //! Slot. Sets current time.\r
+       /*!\r
+        * Slots. Sets current time on the widget. It is used to provide up-to-date time for the widget's\r
+        * TimeDisplayWidget.\r
+        * \param aCurrentTime The current time.\r
+        */\r
+       void setCurrentTime( QTime aCurrentTime );\r
+       //! Slot. Used to indicate changes in the status of the default room.\r
+       /*!\r
+        * Slot. Used to indicate changes in the status of the default room. If the specified until time equals\r
+        * with the end of the day, i.e. there are no further meetings today or the room is busy until the end\r
+        * of the day, then not the until time is shown but a human readable informative message instead.\r
+        * \param aStatus The new status of the meeting room.\r
+        * \param aUntil The new time until the specified status is valid.\r
+        */\r
+       void statusChanged( const Room::Status aStatus, const QTime aUntil );\r
+\r
+private:\r
+       //! Translates the status into human readable text.\r
+       /*!\r
+        * Translates the status into human readable text.\r
+        * \param aStatus The status to be translated.\r
+        * \return The string translation of the status.\r
+        */\r
+       QString statusToText( const Room::Status aStatus );\r
+       //! Creates a palette used to indicate background color based on the specified status.\r
+       /*!\r
+        * Creates a palette used to indicate background color based on the specified status.\r
+        * \param aStatus The status.\r
+        * \return The palette.\r
+        */\r
+       QPalette createPalette( Room::Status aStatus );\r
+\r
+private:\r
+       QLabel *iDefaultRoomLabel;\r
+       QLabel *iStatusLabel;\r
+       QLabel *iUntilTextLabel;\r
+       TimeDisplayWidget *iTimeDisplay;\r
+       QString iTimeFormat;\r
+\r
+       static QTime endOfTheDay;\r
+\r
+};\r
+\r
+#endif /*ROOMSTATUSINDICATORWIDGET_H_*/\r
diff --git a/src/UserInterface/Views/SettingsView.cpp b/src/UserInterface/Views/SettingsView.cpp
new file mode 100644 (file)
index 0000000..caa5cfe
--- /dev/null
@@ -0,0 +1,420 @@
+#include "SettingsView.h"
+
+#include <QTabWidget>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QPushButton>
+#include <QGroupBox>
+#include <QLabel>
+#include <QLineEdit>
+#include <QRadioButton>
+#include <QTimeEdit>
+#include <QListView>
+#include <QList>
+#include <QTime>
+#include <QIntValidator>
+#include <QGridLayout>
+#include <QCheckBox>
+#include "Configuration.h"
+#include "Room.h"
+#include "DisplaySettings.h"
+#include "ConnectionSettings.h"
+#include "StartupSettings.h"
+
+#include <QtDebug>
+
+SettingsView::SettingsView( QWidget *aParent ) :
+               ObservedWidget( aParent )
+{
+       qDebug() << "SettingsView::ctor invoked";
+       // Prepare the tabbed view
+       iTabWidget = new QTabWidget;
+
+       iSettingsTab = initSettingsTab();
+       iWeekViewTab = initWeekViewTab();
+       iResourcesTab = initResourcesTab();
+       iKioskModeTab = initKioskModeTab();
+
+       iTabWidget->addTab( iSettingsTab, tr( "Settings" ) );
+       iTabWidget->addTab( iWeekViewTab, tr( "Weekly View" ) );
+       iTabWidget->addTab( iResourcesTab, tr( "Resources" ) );
+       iTabWidget->addTab( iKioskModeTab, tr( "KIOSK Mode" ) );
+
+       // Prepare the buttons and button layout
+       QHBoxLayout *buttonLayout = new QHBoxLayout;
+       iOkButton = new QPushButton;
+       iOkButton->setText( tr( "OK" ) );
+       iCancelButton = new QPushButton;
+       iCancelButton->setText( tr( "Cancel" ) );
+       buttonLayout->addWidget( iOkButton );
+       buttonLayout->addWidget( iCancelButton );
+
+       // Handle the main layout
+       QVBoxLayout *mainLayout = new QVBoxLayout;
+       mainLayout->addWidget( iTabWidget );
+       mainLayout->addLayout( buttonLayout );
+
+       setLayout( mainLayout );
+
+       // Handle component connections
+       connect( iOkButton, SIGNAL( pressed() ), this, SLOT( okClicked() ) );
+       connect( iCancelButton, SIGNAL( pressed() ), this, SLOT( cancelClicked() ) );
+}
+
+SettingsView::~SettingsView()
+{
+       if ( iTabWidget != 0 )
+       {
+               delete iTabWidget;
+               iTabWidget = 0;
+       }
+       if ( iOkButton != 0 )
+       {
+               delete iOkButton;
+               iOkButton = 0;
+       }
+       if ( iCancelButton != 0 )
+       {
+               delete iCancelButton;
+               iCancelButton = 0;
+       }
+       if ( iSettingsTab != 0 )
+       {
+               delete iSettingsTab;
+               iSettingsTab = 0;
+       }
+       if ( iWeekViewTab != 0 )
+       {
+               delete iWeekViewTab;
+               iWeekViewTab = 0;
+       }
+       if ( iResourcesTab != 0 )
+       {
+               delete iResourcesTab;
+               iResourcesTab = 0;
+       }
+       if ( iKioskModeTab != 0 )
+       {
+               delete iKioskModeTab;
+               iKioskModeTab = 0;
+       }
+       if ( iUserName != 0 )
+       {
+               delete iUserName;
+               iUserName = 0;
+       }
+       if ( iPassword != 0 )
+       {
+               delete iPassword;
+               iPassword = 0;
+       }
+       if ( iServerAddress != 0 )
+       {
+               delete iServerAddress;
+               iServerAddress = 0;
+       }
+       if ( iDayStartTime != 0 )
+       {
+               delete iDayStartTime;
+               iDayStartTime = 0;
+       }
+       if ( iDayEndTime != 0 )
+       {
+               delete iDayEndTime;
+               iDayEndTime = 0;
+       }
+       if ( iFiveDays != 0 )
+       {
+               delete iFiveDays;
+               iFiveDays = 0;
+       }
+       if ( iSevenDays != 0 )
+       {
+               delete iSevenDays;
+               iSevenDays = 0;
+       }
+       if ( iRefreshInterval != 0 )
+       {
+               delete iRefreshInterval;
+               iRefreshInterval = 0;
+       }
+       if ( iPowerSaveEnabled != 0 )
+       {
+               delete iPowerSaveEnabled;
+               iPowerSaveEnabled = 0;
+       }
+       if ( iPowerSaveStartTime != 0 )
+       {
+               delete iPowerSaveStartTime;
+               iPowerSaveStartTime = 0;
+       }
+       if ( iPowerSaveEndTime != 0 )
+       {
+               delete iPowerSaveEndTime;
+               iPowerSaveEndTime = 0;
+       }
+}
+
+QWidget *SettingsView::initSettingsTab()
+{
+       QWidget *widget = new QWidget( iTabWidget );
+
+       // Prepare the widgets that are member variables
+       iUserName = new QLineEdit;
+       iPassword = new QLineEdit;
+       iPassword->setEchoMode( QLineEdit::Password );
+       iServerAddress = new QLineEdit;
+       iRefreshInterval = new QLineEdit;
+       QIntValidator *qiv = new QIntValidator( 0 );
+       iRefreshInterval->setValidator( qiv );
+
+       iUserName->setText( Configuration::instance()->connectionSettings()->username() );
+       iPassword->setText( Configuration::instance()->connectionSettings()->password() );
+       iServerAddress->setText( Configuration::instance()->connectionSettings()->serverUrl().toString() );
+       QString refreshIntervalStr;
+       refreshIntervalStr.setNum( Configuration::instance()->connectionSettings()->refreshInterval() );
+       iRefreshInterval->setText( refreshIntervalStr );
+
+       // Create the group boxes
+       QGroupBox *userInformationGroup = new QGroupBox( tr( "User Information" ) );
+       QGroupBox *serverInformationGroup = new QGroupBox( tr( "Server Information" ) );
+
+       // Prepare the user infromation group box
+       QGridLayout *ugl = new QGridLayout;
+       QLabel *userNameLabel = new QLabel( tr( "Username:" ) );
+       QLabel *passwordLabel = new QLabel( tr( "Password:" ) );
+
+       ugl->addWidget( userNameLabel, 0, 0 );
+       ugl->addWidget( iUserName, 0, 1 );
+       ugl->addWidget( passwordLabel, 1, 0 );
+       ugl->addWidget( iPassword, 1, 1 );
+
+       userInformationGroup->setLayout( ugl );
+
+       // Prepare the server information group box
+       QGridLayout *sgl = new QGridLayout;
+       QLabel *serverURLLabel = new QLabel( tr( "Server URL:" ) );
+       QLabel *refreshLabel = new QLabel( tr( "Refresh interval" ) );
+       QLabel *secondsLabel = new QLabel( tr( "seconds" ) );
+
+       sgl->addWidget( serverURLLabel, 0, 0, 1, 2 );
+       sgl->addWidget( iServerAddress, 0, 1 );
+       sgl->addWidget( refreshLabel, 1, 0 );
+       sgl->addWidget( iRefreshInterval, 1, 1 );
+       sgl->addWidget( secondsLabel, 1, 2 );
+
+       serverInformationGroup->setLayout( sgl );
+
+       // Prepare and set the main layout
+       QVBoxLayout *mainLayout = new QVBoxLayout;
+       mainLayout->addWidget( userInformationGroup );
+       mainLayout->addWidget( serverInformationGroup );
+
+       widget->setLayout( mainLayout );
+
+       return widget;
+}
+
+QWidget *SettingsView::initWeekViewTab()
+{
+       QWidget *widget = new QWidget( iTabWidget );
+
+       // Prepare the member variable widgets
+       iFiveDays = new QRadioButton( tr( "5" ) );
+       iSevenDays = new QRadioButton( tr( "7" ) );
+       iDayStartTime = new QTimeEdit;
+       iDayEndTime = new QTimeEdit;
+
+       if ( Configuration::instance()->displaySettings()->daysInSchedule() == DisplaySettings::WeekdaysInSchedule )
+       {
+               iFiveDays->setChecked( true );
+               iSevenDays->setChecked( false );
+       }
+       else
+       {
+               iFiveDays->setChecked( false );
+               iSevenDays->setChecked( true );
+       }
+       iDayStartTime->setTime( Configuration::instance()->displaySettings()->dayStartsAt() );
+       iDayEndTime->setTime( Configuration::instance()->displaySettings()->dayEndsAt() );
+
+       // Create group box and the grid layout
+       QGroupBox *weeklyInformation = new QGroupBox( tr( "Weekly View" ) );
+       QGridLayout *wgl = new QGridLayout;
+
+       // Prepare the number of days row
+       QLabel *daysLabel = new QLabel( tr( "Days:" ) );
+
+       wgl->addWidget( daysLabel, 0, 0 );
+       wgl->addWidget( iFiveDays, 0, 1 );
+       wgl->addWidget( iSevenDays, 0, 2 );
+
+       // Preare the day starts row
+       QLabel *dayStartsLabel = new QLabel( tr( "Day starts:" ) );
+
+       wgl->addWidget( dayStartsLabel, 1, 0 );
+       wgl->addWidget( iDayStartTime, 1, 1, 1, 2 );
+
+       // Prepare the day ends row
+       QLabel *dayEndsLabel = new QLabel( tr( "Day ends:" ) );
+
+       wgl->addWidget( dayEndsLabel, 2, 0 );
+       wgl->addWidget( iDayEndTime, 2, 1, 1, 2 );
+
+       weeklyInformation->setLayout( wgl );
+
+       QVBoxLayout *mainLayout = new QVBoxLayout;
+       mainLayout->addWidget( weeklyInformation );
+
+       widget->setLayout( mainLayout );
+
+       return widget;
+}
+
+QWidget *SettingsView::initResourcesTab()
+{
+       QWidget *widget = new QWidget( iTabWidget );
+
+       QHBoxLayout *mainLayout = new QHBoxLayout;
+
+       // Available resources
+       QVBoxLayout *availableResourcesLayout = new QVBoxLayout;
+       QLabel *availableResourcesLabel = new QLabel( tr( "Available Resources:" ) );
+       QListView *availableResourcesList = new QListView;
+
+       // Fill the list
+       QList<Room*> rooms = Configuration::instance()->rooms();
+       for ( int i = 0; i < rooms.count(); i++ )
+       {
+               Room *tmp_room = ( Room * ) rooms.at( i );
+               qDebug() << "Room: " << tmp_room->name();
+       }
+
+       availableResourcesLayout->addWidget( availableResourcesLabel );
+       availableResourcesLayout->addWidget( availableResourcesList );
+
+       // Selected resources
+       QVBoxLayout *selectedResourcesLayout = new QVBoxLayout;
+       QLabel *selectedResourcesLabel = new QLabel( tr( "Selected Resources:" ) );
+       QListView *selectedResourcesList = new QListView;
+
+       selectedResourcesLayout->addWidget( selectedResourcesLabel );
+       selectedResourcesLayout->addWidget( selectedResourcesList );
+
+       // Button lauout
+       QVBoxLayout *controlButtonsLayout = new QVBoxLayout;
+       QPushButton *addButton = new QPushButton( tr( "->" ) );
+       QPushButton *removeButton = new QPushButton( tr( "<-" ) );
+       controlButtonsLayout->addWidget( addButton );
+       controlButtonsLayout->addWidget( removeButton );
+
+       // Prepare main layout
+       mainLayout->addLayout( availableResourcesLayout );
+       mainLayout->addLayout( controlButtonsLayout );
+       mainLayout->addLayout( selectedResourcesLayout );
+
+       widget->setLayout( mainLayout );
+
+       return widget;
+}
+
+QWidget *SettingsView::initKioskModeTab()
+{
+       QWidget *widget = new QWidget( iTabWidget );
+
+       // Prepare member variable widgets
+       iPowerSaveEnabled = new QCheckBox( tr( "Power save enabled" ) );
+       iPowerSaveStartTime = new QTimeEdit;
+       iPowerSaveEndTime = new QTimeEdit;
+
+       if ( Configuration::instance()->startupSettings()->isPowersavingEnabled() )
+       {
+               iPowerSaveEnabled->setChecked( true );
+       }
+       else
+       {
+               iPowerSaveEnabled->setChecked( false );
+       }
+       iPowerSaveStartTime->setTime( Configuration::instance()->startupSettings()->turnOnAt() );
+       iPowerSaveEndTime->setTime( Configuration::instance()->startupSettings()->turnOffAt() );
+
+       // Prepare the admin password box
+       QGroupBox *adminPasswordGroup = new QGroupBox( tr( "Admin Password" ) );
+       QLabel *oldPwdLabel = new QLabel( tr( "Old password:" ) );
+       QLabel *newPwdLabel = new QLabel( tr( "New password:" ) );
+       QLabel *confirmPwdLabel = new QLabel( tr( "Confirm password:" ) );
+       QPushButton *applyPwdButton = new QPushButton( tr( "Apply" ) );
+
+       QLineEdit *oldPwdEdit = new QLineEdit;
+       QLineEdit *newPwdEdit = new QLineEdit;
+       QLineEdit *confirmPwdEdit = new QLineEdit;
+
+       oldPwdEdit->setEchoMode( QLineEdit::Password );
+       newPwdEdit->setEchoMode( QLineEdit::Password );
+       confirmPwdEdit->setEchoMode( QLineEdit::Password );
+
+       QGridLayout *agl = new QGridLayout;
+
+       agl->addWidget( oldPwdLabel, 0, 0 );
+       agl->addWidget( oldPwdEdit, 0, 1 );
+       agl->addWidget( newPwdLabel, 1, 0 );
+       agl->addWidget( newPwdEdit, 1, 1 );
+       agl->addWidget( confirmPwdLabel, 2, 0 );
+       agl->addWidget( confirmPwdEdit, 2, 1 );
+       agl->addWidget( applyPwdButton, 3, 0, 1, 2, Qt::AlignRight );
+
+       adminPasswordGroup->setLayout( agl );
+
+       // Prepare the power save options
+       QGroupBox *powerSaveGroup = new QGroupBox( tr( "Power Save" ) );
+       QLabel *switchedOnLabel = new QLabel( tr( "Switched on from:" ) );
+       QLabel *toLabel = new QLabel( tr( "to" ) );
+       QGridLayout *psgl = new QGridLayout;
+
+       psgl->addWidget( iPowerSaveEnabled, 0, 0, 1, 4, Qt::AlignLeft );
+       psgl->addWidget( switchedOnLabel, 1, 0 );
+       psgl->addWidget( iPowerSaveStartTime, 1, 1 );
+       psgl->addWidget( toLabel, 1, 2 );
+       psgl->addWidget( iPowerSaveEndTime, 1, 3 );
+
+       powerSaveGroup->setLayout( psgl );
+
+       // Prepare the main layout
+       QVBoxLayout *mainLayout = new QVBoxLayout;
+       mainLayout->addWidget( adminPasswordGroup );
+       mainLayout->addWidget( powerSaveGroup );
+
+       widget->setLayout( mainLayout );
+
+       return widget;
+}
+
+void SettingsView::okClicked()
+{
+       qDebug() << "[SettingsView::okClicked] <Invoked>";
+
+       // Collect the configration data
+       QTime calendarStart = iDayStartTime->time();
+       QTime calendarEnd = iDayEndTime->time();
+       QTime powerSaveStart = iPowerSaveStartTime->time();
+       QTime powerSaveEnd = iPowerSaveEndTime->time();
+
+       QString userName = iUserName->text();
+       QString password = iPassword->text();
+       QString serverAddress = iServerAddress->text();
+       QString refreshInterval = iRefreshInterval->text();
+
+       bool fiveDays = iFiveDays->isChecked();
+       bool sevenDays = iSevenDays->isChecked();
+       bool powerSaveEnabled = iPowerSaveEnabled->isChecked();
+
+       // TODO : Set the values to configuration and save it
+
+       close();
+}
+
+void SettingsView::cancelClicked()
+{
+       qDebug() << "[SettingsView::cancelClicked] <Invoked>";
+       close();
+}
diff --git a/src/UserInterface/Views/SettingsView.h b/src/UserInterface/Views/SettingsView.h
new file mode 100644 (file)
index 0000000..8b9bbeb
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef SETTINGSVIEW_H_
+#define SETTINGSVIEW_H_
+
+#include "ObservedWidget.h"
+
+class QTabWidget;
+class QPushButton;
+class QLineEdit;
+class QTimeEdit;
+class QRadioButton;
+class QCheckBox;
+
+//! User interface class. Shows the settings view and handles configuration changes.
+class SettingsView : public ObservedWidget
+{
+       Q_OBJECT
+
+public:
+       //! Constructor.
+       /*!
+        * Constructor to initialize and prepare the settings view. This calls internally
+        * the helper methods to initialize individual setting tabs.
+        * \param Parent component.
+        */
+       SettingsView( QWidget *aParent = 0 );
+       //! Destructor.
+       virtual ~SettingsView();
+
+private slots:
+       //! Slot to handle the Ok button pressing.
+       void okClicked();
+       //! Slot to handle the cancel button pressing.
+       void cancelClicked();
+
+private:
+       //! Initialize "Settings" tab.
+       QWidget *initSettingsTab();
+       //! Initialize "Week View" tab.
+       QWidget *initWeekViewTab();
+       //! Intialize "Resources" tab.
+       QWidget *initResourcesTab();
+       //! Initialize "KIOSK Mode" tab.
+       QWidget *initKioskModeTab();
+
+       //! The tabbed settings view component.
+       QTabWidget *iTabWidget;
+       //! OK button to dismiss the settings view with saving the settings.
+       QPushButton *iOkButton;
+       //! Cancel button to dismiss the settings view without saving settings.
+       QPushButton *iCancelButton;
+       //! Settings tab.
+       QWidget *iSettingsTab;
+       //! Week View tab.
+       QWidget *iWeekViewTab;
+       //! Resources tab.
+       QWidget *iResourcesTab;
+       //! KIOSK Mode tab.
+       QWidget *iKioskModeTab;
+
+       //! User name to the remote server.
+       QLineEdit *iUserName;
+       //! Password to the remote server.
+       QLineEdit *iPassword;
+       //! Remote server address.
+       QLineEdit *iServerAddress;
+       //! Refresh interval in seconds.
+       QLineEdit *iRefreshInterval;
+       //! When the day starts in the calendar view.
+       QTimeEdit *iDayStartTime;
+       //! When the day ends in the calendar view.
+       QTimeEdit *iDayEndTime;
+       //! Selection for showing five days in the calendar.
+       QRadioButton *iFiveDays;
+       //! Selection for showing seven days in the calendar.
+       QRadioButton *iSevenDays;
+       //! Power saving enabling.
+       QCheckBox *iPowerSaveEnabled;
+       //! Start time for activating power save.
+       QTimeEdit *iPowerSaveStartTime;
+       //! End time for deactivating power save.
+       QTimeEdit *iPowerSaveEndTime;
+};
+
+#endif /*SETTINGSVIEW_H_*/
diff --git a/src/UserInterface/Views/WeeklyViewWidget.cpp b/src/UserInterface/Views/WeeklyViewWidget.cpp
new file mode 100644 (file)
index 0000000..b33e517
--- /dev/null
@@ -0,0 +1,202 @@
+#include "WeeklyViewWidget.h"\r
+\r
+#include <QLabel>\r
+#include <QPushButton>\r
+#include <QVBoxLayout>\r
+#include <QPixmap>\r
+#include <QTimer>\r
+#include <QKeyEvent>\r
+#include <QTabletEvent>\r
+#include "Configuration.h"\r
+#include "DisplaySettings.h"\r
+#include "Meeting.h"\r
+#include "Room.h"\r
+#include "MeetingRoomCombo.h"\r
+#include "DigitalTimeDisplayWidget.h"\r
+#include "ScheduleWidget.h"\r
+#include "ToolBox.h"\r
+#include "MeetingInfoDialog.h"\r
+\r
+#include <QtDebug>\r
+\r
+WeeklyViewWidget::WeeklyViewWidget( QDateTime aCurrentDateTime, Configuration *aConfiguration, QWidget *aParent ) :\r
+               ObservedWidget( aParent ), iConfiguration( aConfiguration )\r
+{\r
+\r
+       // *****************************************\r
+       //              Construct all the needed widgets\r
+       QFont importantTextFont;\r
+       importantTextFont.setBold( true );\r
+       importantTextFont.setPointSize( 20 );\r
+\r
+       QFont regularTextFont;\r
+       regularTextFont.setBold( true );\r
+       regularTextFont.setPointSize( 12 );\r
+\r
+       iSettingsButton = new QPushButton;\r
+       iSettingsButton->setIcon( QPixmap( ":button_settings" ) );\r
+       iSettingsButton->setFixedWidth( 36 );\r
+       connect( iSettingsButton, SIGNAL( clicked() ), this, SIGNAL( showSettingsView() ) );\r
+\r
+       iCurrentDayLabel = ToolBox::createLabel( aCurrentDateTime.toString( iConfiguration->displaySettings()->dateFormat() ), regularTextFont );\r
+       iCurrentWeekLabel = ToolBox::createLabel( tr( "Wk %1" ).arg( aCurrentDateTime.date().weekNumber() ), regularTextFont );\r
+\r
+       iRoomsCombo = new MeetingRoomCombo( iConfiguration->rooms(), this );\r
+       iRoomsCombo->setCurrentRoom( iConfiguration->defaultRoom() );\r
+       connect( iRoomsCombo, SIGNAL( observedEventDetected() ), this, SIGNAL( observedEventDetected() ) );\r
+\r
+       iTimeDisplay = new DigitalTimeDisplayWidget( aCurrentDateTime.time(), iConfiguration->displaySettings()->timeFormat(), this );\r
+       iTimeDisplay->setFrameVisible( false );\r
+       iTimeDisplay->setFont( regularTextFont );\r
+       connect( iTimeDisplay, SIGNAL( observedEventDetected() ), this, SIGNAL( observedEventDetected() ) );\r
+\r
+       iSchedule = new ScheduleWidget( aCurrentDateTime, iConfiguration->displaySettings(), this );\r
+       connect( iSchedule, SIGNAL( shownWeekChanged( QDate ) ), this, SIGNAL( shownWeekChanged( QDate ) ) );\r
+       connect( iSchedule, SIGNAL( observedEventDetected() ), this, SIGNAL( observedEventDetected() ) );\r
+       connect( iSchedule, SIGNAL( meetingActivated( Meeting* ) ), this, SIGNAL( meetingActivated( Meeting* ) ) );\r
+\r
+       iPreviousWeekButton = new QPushButton( this );\r
+       iPreviousWeekButton->setText( tr( "<<" ) );\r
+       iPreviousWeekButton->setFixedWidth( 60 );\r
+       connect( iPreviousWeekButton, SIGNAL( clicked() ), iSchedule, SLOT( showPreviousWeek() ) );\r
+\r
+       iCurrentWeekButton = new QPushButton( this );\r
+       iCurrentWeekButton->setFixedWidth( 100 );\r
+       iCurrentWeekButton->setText( tr( "Current" ) );\r
+       connect( iCurrentWeekButton, SIGNAL( clicked() ), iSchedule, SLOT( showCurrentWeek() ) );\r
+\r
+       iNextWeekButton = new QPushButton( this );\r
+       iNextWeekButton->setFixedWidth( 60 );\r
+       iNextWeekButton->setText( tr( ">>" ) );\r
+       connect( iNextWeekButton, SIGNAL( clicked() ), iSchedule, SLOT( showNextWeek() ) );\r
+\r
+       // **********************************\r
+       //              Create the view's layout\r
+       QHBoxLayout *tableLayout = new QHBoxLayout;\r
+       tableLayout->addWidget( iSchedule );\r
+\r
+       QHBoxLayout *bottomLayout = new QHBoxLayout;\r
+       bottomLayout->addWidget( iRoomsCombo );\r
+       bottomLayout->addWidget( iTimeDisplay );\r
+       QVBoxLayout *dateLayout = new QVBoxLayout;\r
+       dateLayout->addWidget( iCurrentDayLabel );\r
+       dateLayout->addWidget( iCurrentWeekLabel );\r
+       bottomLayout->addLayout( dateLayout );\r
+       bottomLayout->addWidget( iPreviousWeekButton );\r
+       bottomLayout->addWidget( iCurrentWeekButton );\r
+       bottomLayout->addWidget( iNextWeekButton );\r
+       bottomLayout->addWidget( iSettingsButton );\r
+\r
+       QVBoxLayout *mainLayout = new QVBoxLayout;\r
+       mainLayout->addLayout( tableLayout );\r
+       mainLayout->addLayout( bottomLayout );\r
+       setLayout( mainLayout );\r
+\r
+       QPalette palette;\r
+       palette.setColor( QPalette::Window, Qt::white );\r
+       palette.setColor( QPalette::Foreground, Qt::darkGray );\r
+       setPalette( palette );\r
+\r
+       // ******************************************\r
+       //              Handle all the signal connections\r
+       // TODO : this solution if interaction monitoring is not elegant enough\r
+       connect( iPreviousWeekButton, SIGNAL( clicked() ), this, SIGNAL( observedEventDetected() ) );\r
+       connect( iCurrentWeekButton, SIGNAL( clicked() ), this, SIGNAL( observedEventDetected() ) );\r
+       connect( iNextWeekButton, SIGNAL( clicked() ), this, SIGNAL( observedEventDetected() ) );\r
+       connect( iRoomsCombo, SIGNAL( currentRoomChanged( Room * ) ), this, SIGNAL( observedEventDetected() ) );\r
+       connect( iRoomsCombo, SIGNAL( currentIndexChanged( int ) ), this, SIGNAL( observedEventDetected() ) );\r
+       // TODO: connect RoomCombo signals to change meetings data.\r
+       connect( iRoomsCombo, SIGNAL( currentRoomChanged( Room * ) ), iSchedule, SLOT( clear() ) );\r
+       connect( iRoomsCombo, SIGNAL( currentRoomChanged( Room * ) ), this, SIGNAL( currentRoomChanged( Room * ) ) );\r
+       connect( iRoomsCombo, SIGNAL( currentRoomChanged( Room * ) ), iSchedule, SLOT( refresh() ) );\r
+}\r
+\r
+WeeklyViewWidget::~WeeklyViewWidget()\r
+{\r
+       if ( iRoomsCombo )\r
+       {\r
+               delete iRoomsCombo;\r
+               iRoomsCombo = 0;\r
+       }\r
+       if ( iTimeDisplay )\r
+       {\r
+               delete iTimeDisplay;\r
+               iTimeDisplay = 0;\r
+       }\r
+       if ( iSchedule )\r
+       {\r
+               delete iSchedule;\r
+               iSchedule = 0;\r
+       }\r
+       if ( iCurrentDayLabel )\r
+       {\r
+               delete iCurrentDayLabel;\r
+               iCurrentDayLabel = 0;\r
+       }\r
+       if ( iCurrentWeekLabel )\r
+       {\r
+               delete iCurrentWeekLabel;\r
+               iCurrentWeekLabel = 0;\r
+       }\r
+       if ( iPreviousWeekButton )\r
+       {\r
+               delete iPreviousWeekButton;\r
+               iPreviousWeekButton = 0;\r
+       }\r
+       if ( iCurrentWeekButton )\r
+       {\r
+               delete iCurrentWeekButton;\r
+               iCurrentWeekButton = 0;\r
+       }\r
+       if ( iNextWeekButton )\r
+       {\r
+               delete iNextWeekButton;\r
+               iNextWeekButton = 0;\r
+       }\r
+       if ( iSettingsButton )\r
+       {\r
+               delete iSettingsButton;\r
+               iSettingsButton = 0;\r
+       }\r
+}\r
+\r
+Meeting* WeeklyViewWidget::currentMeeting()\r
+{\r
+       return iSchedule->currentMeeting();\r
+}\r
+\r
+Room* WeeklyViewWidget::currentRoom()\r
+{\r
+       return iRoomsCombo->currentRoom();\r
+}\r
+\r
+void WeeklyViewWidget::setCurrentDateTime( QDateTime aCurrentDateTime )\r
+{\r
+       iCurrentDayLabel->setText( aCurrentDateTime.date().toString( iConfiguration->displaySettings()->dateFormat() ) );\r
+       \r
+       iCurrentWeekLabel->setText( tr( "Wk %1" ).arg( aCurrentDateTime.date().weekNumber() ) );\r
+\r
+       iTimeDisplay->setTime( aCurrentDateTime.time() );\r
+\r
+       iSchedule->setCurrentDateTime( aCurrentDateTime );\r
+}\r
+\r
+void WeeklyViewWidget::insertMeeting( Meeting *aMeeting )\r
+{\r
+       iSchedule->insertMeeting( aMeeting );\r
+}\r
+\r
+void WeeklyViewWidget::deleteMeeting( Meeting *aMeeting )\r
+{\r
+       iSchedule->removeMeeting( aMeeting );\r
+}\r
+\r
+void WeeklyViewWidget::updateMeeting( Meeting *aMeeting )\r
+{\r
+       iSchedule->updateMeeting( aMeeting );\r
+}\r
+\r
+QDate WeeklyViewWidget::beginnigOfShownWeek()\r
+{\r
+       return iSchedule->beginningOfShownWeek();\r
+}\r
diff --git a/src/UserInterface/Views/WeeklyViewWidget.h b/src/UserInterface/Views/WeeklyViewWidget.h
new file mode 100644 (file)
index 0000000..f0da141
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef WEEKLYVIEWWIDGET_H_\r
+#define WEEKLYVIEWWIDGET_H_\r
+\r
+#include "ObservedWidget.h"\r
+#include <QDateTime>\r
+\r
+class QLabel;\r
+class QPushButton;\r
+class MeetingRoomCombo;\r
+class TimeDisplayWidget;\r
+class ScheduleWidget;\r
+class Configuration;\r
+class Meeting;\r
+class Room;\r
+\r
+//! Userinterface class. Shows a weekly calendar for the selected room, provides date and time information.\r
+/*!\r
+ * UserInterface class. Shows the current date and time and selected week's calendar for\r
+ * selected meeting room. User can select meeting room, browse weeks back and forth, and can navigate\r
+ * back to the current week.\r
+ */\r
+class WeeklyViewWidget : public ObservedWidget\r
+{\r
+       Q_OBJECT\r
+\r
+public:\r
+       //! Constructor.\r
+       /*!\r
+        * Constructor to initialize an WeeklyViewWidget instance.\r
+        * \param aCurrentDateTime\r
+        * \param aConfiguration Pointer to the configuration object. Not owned.\r
+        * \param aParent Pointer to the parent widget.\r
+        */\r
+       WeeklyViewWidget( QDateTime aCurrentDateTime, Configuration *aConfiguration, QWidget *aParent = 0 );\r
+       //! Destructor.\r
+       virtual ~WeeklyViewWidget();\r
+\r
+       //! Current meeting\r
+       /*!\r
+        * Returns the current meeting if any\r
+        * \return Current meeting if any, otherwise null pointer\r
+        */\r
+       Meeting* currentMeeting();\r
+       //! Current room\r
+       /*!\r
+        * Returns the currently selected meeting room.\r
+        * \return Selected meeting room.\r
+        */\r
+       Room* currentRoom();\r
+\r
+       //! First day of week currently displayd\r
+       /*!\r
+        * Returns the first day of week currently displayd.\r
+        * \return First day of week.\r
+        */\r
+       QDate beginnigOfShownWeek();\r
+\r
+signals:\r
+       //! Signals change of the meeting room.\r
+       /*!\r
+        * Signal is emited when meeting room is changed.\r
+        * \param aNewRoom Selected meeting room.\r
+        */\r
+       void currentRoomChanged( Room *aNewRoom );\r
+       //! Signals change of the current meeting.\r
+       /*!\r
+        * Signal is emited when new meeting is started.\r
+        * \param aNewMeeting Meeting that has been started.\r
+        */\r
+       void currentMeetingChanged( Meeting *aNewMeeting );\r
+       //! Meeting activated.\r
+       /*!\r
+        * Signal is emitted when a meeting is clicked by the user.\r
+        * \param aMeeting actived meeting.\r
+        */\r
+       void meetingActivated( Meeting *aMeeting );\r
+       //! Signals creation of new meeting.\r
+       /*!\r
+        * Signal is emited when new meeting is created.\r
+        * \param aMeeting Meeting that has been created.\r
+        * \param aUsername User who created the meeting.\r
+        * \param aPassword Password of the "aUsername"\r
+        */\r
+       void meetingToCreate( Meeting *aMeeting, const QString &aUsername, const QString &aPassword );\r
+       //! Signals deletion of a meeting.\r
+       /*!\r
+        * Signal is emited when meeting is deleted.\r
+        * \param aMeeting Deleted meeting.\r
+        * \param aUsername User who deleted the meeting.\r
+        * \param aPassword Password of the "aUsername"\r
+        */\r
+       void meetingToDelete( Meeting *aMeeting, const QString &aUsername, const QString &aPassword );\r
+       //! Signals modifications of a meeting.\r
+       /*!\r
+        * Signal is emited when meeting is modified.\r
+        * \param aMeeting Modified meeting.\r
+        * \param aUsername User who modified the meeting.\r
+        * \param aPassword Password of the "aUsername"\r
+        */\r
+       void meetingToUpdate( Meeting *aMeeting, const QString &aUsername, const QString &aPassword );\r
+\r
+       //! Signals\r
+       /*!\r
+        * Signal is emited when settings button is clicked.\r
+        */\r
+       void showSettingsView();\r
+       \r
+       //! Signal. Emitted if the shown week has been changed.\r
+       /*!\r
+        * Signal. Emitted if the shown week has been changed.
+        * \param aDate The first date of the shown week.
+        */
+       void shownWeekChanged( QDate aDate );
+\r
+public slots:\r
+       //! Sets the date and time\r
+       /*!\r
+        * Sets the current date and time\r
+        * \param aCurrentDateTime Date and time to be displayd.\r
+        */\r
+       void setCurrentDateTime( QDateTime aCurrentDateTime );\r
+       //! Insert meeting\r
+       /*!\r
+        * Inserts new meeting into the calendar\r
+        * \param aMeeting Meeting to be inserted.\r
+        */\r
+       void insertMeeting( Meeting *aMeeting );\r
+       //! Delete meeting\r
+       /*!\r
+        * Removes meeting from the calendar\r
+        * \param aMeeting Meeting to be deleted.\r
+        */\r
+       void deleteMeeting( Meeting *aMeeting );\r
+       //! Update meeting\r
+       /*!\r
+        * Updates the display of given meeting in calendar.\r
+        * \param aMeeting Meeting to be updated.\r
+        */\r
+       void updateMeeting( Meeting *aMeeting );\r
+\r
+private:\r
+       //! Displays the selectable meeting rooms.\r
+       MeetingRoomCombo *iRoomsCombo;\r
+       //! Displays the time.\r
+       TimeDisplayWidget *iTimeDisplay;\r
+       //! Displays the calendar.\r
+       ScheduleWidget *iSchedule;\r
+       //! Displays the date.\r
+       QLabel *iCurrentDayLabel;\r
+       //! Displays the week number.\r
+       QLabel *iCurrentWeekLabel;\r
+       //! Button used to display previous week's calendar.\r
+       QPushButton *iPreviousWeekButton;\r
+       //! Button used to display current week's calendar.\r
+       QPushButton *iCurrentWeekButton;\r
+       //! Button used to display next week's calendar.\r
+       QPushButton *iNextWeekButton;\r
+       //! Settings button. TODO : Correct widget is needed!!\r
+       QPushButton *iSettingsButton;\r
+       //! About button. TODO : Correct widget is needed!!\r
+       QPushButton *iAboutButton;\r
+       /* !\r
+        * Pointer to configuration object.\r
+        * Contains configurable data and IS NOT OWNED by the widget.\r
+        */\r
+       Configuration *iConfiguration;\r
+};\r
+\r
+#endif /*WEEKLYVIEWWIDGET_H_*/\r
diff --git a/src/UserInterface/WindowManager.cpp b/src/UserInterface/WindowManager.cpp
new file mode 100644 (file)
index 0000000..edb7b95
--- /dev/null
@@ -0,0 +1,272 @@
+#include "WindowManager.h"
+
+#include <QApplication>
+#include <QTimer>
+#include "Configuration.h"
+#include "DisplaySettings.h"
+#include "Meeting.h"
+#include "Room.h"
+#include "Engine.h"
+#include "Clock.h"
+#include "WeeklyViewWidget.h"
+#include "RoomStatusIndicatorWidget.h"
+#include "MeetingInfoDialog.h"
+#include "PopUpMessageBox.h"
+#include "DeviceManager.h"
+#include "SettingsView.h"
+
+#include <QtDebug>
+
+const int IDLE_TIME_MULTIPLIER = 60000; // Multiplies milliseconds to minutes
+
+WindowManager::WindowManager() :
+               QObject(),
+               iApplicationName( tr( "Qt Meetings" ) ),
+               iWeeklyView( 0 ),
+               iRoomStatusView( 0 ),
+               iMeetingInfo( 0 )
+{
+       iEngine = new Engine;
+       connect( iEngine, SIGNAL( initializationFailed() ), this, SLOT( closeApplication() ) );
+       connect( this, SIGNAL( roomStatusInfoNeeded( Room * ) ), iEngine, SLOT( roomStatusInfoNeeded( Room * ) ) );
+       connect( iEngine, SIGNAL( roomStatusChanged( Room *, Room::Status, QTime ) ), this, SLOT( roomStatusChanged( Room *, Room::Status, QTime ) ) );
+       connect( iEngine->clock(), SIGNAL( tick( QDateTime ) ), this, SLOT( distributeDateTimeInfo( QDateTime ) ) );
+       connect( iEngine, SIGNAL( error( QString ) ), this, SLOT( error( QString ) ) );
+       connect( iEngine->deviceManager(), SIGNAL( changeModeOrdered( DeviceManager::OperationMode ) ), this, SLOT( changeModeOrdered( DeviceManager::OperationMode ) ) );
+       
+       iWeeklyView = new WeeklyViewWidget( QDateTime::currentDateTime(), iEngine->configuration() );
+       iWeeklyView->setWindowTitle( iApplicationName );
+       connect( iEngine, SIGNAL( meetingAdded( Meeting * ) ), iWeeklyView, SLOT( insertMeeting( Meeting * ) ) );
+       connect( iEngine, SIGNAL( meetingDeleted( Meeting * ) ), iWeeklyView, SLOT( deleteMeeting( Meeting * ) ) );
+       connect( iWeeklyView, SIGNAL( observedEventDetected() ), this, SLOT( observedEventDetected() ) );
+       connect( iWeeklyView, SIGNAL( meetingActivated( Meeting * ) ), iEngine, SLOT( fetchMeetingDetails( Meeting* ) ) );
+       connect( iEngine, SIGNAL( meetingDetailsFetched( Meeting* ) ), this, SLOT( showMeetingInfo( Meeting * ) ) );
+       connect( iWeeklyView, SIGNAL( currentRoomChanged( Room * ) ), iEngine, SLOT( currentRoomChanged( Room * ) ) );
+       connect( iWeeklyView, SIGNAL( currentRoomChanged( Room * ) ), this, SLOT( fetchMeetings( Room * ) ) );
+       // TODO: fetch meetings for specific week
+       connect( iWeeklyView, SIGNAL( shownWeekChanged( QDate ) ), this, SLOT( fetchMeetings( QDate ) ) );
+
+       iIdleTimeCounter = new QTimer();
+       iIdleTimeCounter->setSingleShot( true );
+       iIdleTimeCounter->setInterval( IDLE_TIME_MULTIPLIER * iEngine->configuration()->displaySettings()->screensaver() );
+       iIdleTimeCounter->start();
+       connect( iIdleTimeCounter, SIGNAL( timeout() ), this, SLOT( showRoomStatus() ) );
+
+       if( iEngine->deviceManager()->currentOperationMode() == DeviceManager::KioskMode )
+               iWeeklyView->setWindowState( Qt::WindowFullScreen );
+       else
+               iWeeklyView->setWindowState( Qt::WindowMaximized );
+       showWeeklyView();
+
+       //QTimer::singleShot( 0, this, SLOT( closeApplication() ) );
+}
+
+WindowManager::~WindowManager()
+{
+       if ( iWeeklyView != 0 )
+       {
+               delete iWeeklyView;
+               iWeeklyView = 0;
+       }
+
+       if ( iRoomStatusView != 0 )
+       {
+               delete iRoomStatusView;
+               iRoomStatusView = 0;
+       }
+
+       if ( iMeetingInfo != 0 )
+       {
+               delete iMeetingInfo;
+               iMeetingInfo = 0;
+       }
+
+       if ( iIdleTimeCounter )
+       {
+               iIdleTimeCounter->stop();
+               delete iIdleTimeCounter;
+               iIdleTimeCounter = 0;
+       }
+}
+
+void WindowManager::closeApplication()
+{
+       qDebug() << "WindowManager::closeApplication\tclose application";
+       // closes application after 1 second
+       QTimer::singleShot( 1000, QApplication::instance(), SLOT( quit() ) );
+}
+
+void WindowManager::distributeDateTimeInfo( QDateTime aCurrentDateTime )
+{
+       if ( iRoomStatusView != 0 && iRoomStatusView->isActiveWindow() )
+       {
+               iRoomStatusView->setCurrentTime( aCurrentDateTime.time() );
+       }
+
+       if ( iWeeklyView != 0 && iWeeklyView->isActiveWindow() )
+       {
+               iWeeklyView->setCurrentDateTime( aCurrentDateTime );
+       }
+}
+
+void WindowManager::roomStatusChanged( Room *aRoom, Room::Status aStatus, QTime aTime )
+{
+       // currently works only for default room
+       if ( aRoom->equals( *(iEngine->defaultRoom()) ) )
+       {
+               if ( iRoomStatusView == 0 )
+               {
+                       iRoomStatusView = new RoomStatusIndicatorWidget( aRoom, aStatus, aTime, iEngine->configuration()->displaySettings()->timeFormat() );
+                       iRoomStatusView->setWindowTitle( iApplicationName );
+                       connect( iRoomStatusView, SIGNAL( observedEventDetected() ), this, SLOT( observedEventDetected() ) );
+                       if( iEngine->deviceManager()->currentOperationMode() == DeviceManager::KioskMode )
+                               iRoomStatusView->setWindowState( Qt::WindowFullScreen );
+                       else
+                               iRoomStatusView->setWindowState( Qt::WindowMaximized );
+               }
+               else
+               {
+                       iRoomStatusView->statusChanged( aStatus, aTime );
+               }
+
+               if ( !iWeeklyView->isVisible() && !iRoomStatusView->isVisible() )
+               {
+                       showRoomStatus();
+               }
+       }
+}
+
+void WindowManager::showRoomStatus()
+{
+       qDebug() << "WindowManager::showRoomStatus";
+
+       if ( iRoomStatusView == 0 )
+       {
+               iEngine->roomStatusInfoNeeded( iWeeklyView->currentRoom() );
+       }
+       else
+       {
+               iRoomStatusView->show();
+               if ( iWeeklyView->isVisible() )
+               {
+                       iWeeklyView->hide();
+               }
+               /* Causes SEGMENTATION FAULT
+               if ( iSettingsView->isVisible() )
+               {
+                       iSettingsView->hide();
+               }
+               */
+       }
+
+       // closing/deleting meeting info dialog
+       if ( iMeetingInfo != 0 )
+       {
+               iMeetingInfo->hide();
+       }
+}
+
+void WindowManager::showWeeklyView()
+{
+       qDebug() << "WindowManager::showWeeklyView";
+       if ( iRoomStatusView != 0 && iRoomStatusView->isVisible() )
+       {
+               iRoomStatusView->hide();
+       }
+
+       iWeeklyView->show();
+}
+
+void WindowManager::showMeetingInfo( Meeting *aMeeting )
+{
+       iMeetingInfo = new MeetingInfoDialog( aMeeting );
+       // Display modal dialog
+       iMeetingInfo->exec();
+
+       delete iMeetingInfo;
+       iMeetingInfo = 0;
+}
+
+void WindowManager::showSettingsView()
+{
+       // TODO : give the Torspo for the person who was responsible to write this method
+}
+
+void WindowManager::error( const QString &aErrorMessage )
+{
+       qDebug() << "WindowManager::showErrorPopup";
+
+       PopUpMessageBox::error( 0, aErrorMessage );
+}
+
+void WindowManager::observedEventDetected()
+{
+       // if event was detected on room status view
+       if ( iRoomStatusView != 0 && iRoomStatusView->isVisible() )
+       {
+               // show weekly view
+               showWeeklyView();
+       }
+       // otherwise
+       else
+       {
+               // prepare to restart idle counter
+               if ( iIdleTimeCounter->isActive() )
+               {
+                       iIdleTimeCounter->stop();
+               }
+       }
+       // (re)start idle counter
+       iIdleTimeCounter->start();
+}
+
+void WindowManager::fetchMeetings( Room * aRoom )
+{
+       QDateTime from( iWeeklyView->beginnigOfShownWeek() );
+       QDateTime to( from.addDays( 8 ) );
+       qDebug() << "WindowManager::fetchMeetings from " << from.toString( "d.m. h:mm" )
+       << " to " << to.toString( "d.m. h:mm" );
+       iEngine->fetchMeetings( from, to, aRoom );
+}
+
+void WindowManager::fetchMeetings( QDate aFrom )
+{
+       QDateTime from( aFrom );
+       QDateTime to( aFrom.addDays( 7 ), QTime( 23, 59 ) );
+       qDebug() << "WindowManager::fetchMeetings from " << from.toString( "d.m. h:mm" )
+       << " to " << to.toString( "d.m. h:mm" );
+       iEngine->fetchMeetings( from, to, iWeeklyView->currentRoom() );
+}
+
+void WindowManager::changeModeOrdered( DeviceManager::OperationMode aMode )
+{
+       QString message = tr( "You are about to change operation mode to %1." )
+                               .arg( iEngine->deviceManager()->operationModeToString( aMode ) );
+       PasswordDialog *dlg = PasswordDialog::query( 0, iEngine->configuration()->adminPassword(), message );
+       qDebug() << "WindowManager::changeModeOrdered/tpassword: " << iEngine->configuration()->adminPassword();
+       //TODO make this modal!!!
+       connect( dlg, SIGNAL( passwordEntered( PasswordDialog::PasswordStatus ) ),
+                  this, SLOT( passwordEntered( PasswordDialog::PasswordStatus ) ) );
+}
+
+void WindowManager::passwordEntered( PasswordDialog::PasswordStatus aPasswordStatus )
+{
+       switch ( aPasswordStatus )
+       {
+               case PasswordDialog::Correct :
+               {
+                       iEngine->deviceManager()->changeMode( true );
+                       break;
+               }
+               case PasswordDialog::Incorrect :
+               {
+                       error( tr( "Incorrect password." ) );
+                       iEngine->deviceManager()->changeMode( false );
+                       break;
+               }
+               default : //case PasswordDialog::Canceled
+               {
+                       iEngine->deviceManager()->changeMode( false );
+               }
+       }
+}
diff --git a/src/UserInterface/WindowManager.h b/src/UserInterface/WindowManager.h
new file mode 100644 (file)
index 0000000..f1f72b5
--- /dev/null
@@ -0,0 +1,125 @@
+#ifndef WINDOWMANAGER_H_\r
+#define WINDOWMANAGER_H_\r
+\r
+#include <QObject>\r
+#include <QTime>\r
+#include "Room.h"\r
+#include "Meeting.h"\r
+#include "PasswordDialog.h"\r
+#include "DeviceManager.h"\r
+\r
+class QTimer;\r
+class RoomStatusIndicatorWidget;\r
+class WeeklyViewWidget;\r
+class Engine;\r
+class MeetingInfoDialog;\r
+class SettingsView;\r
+\r
+//! UserInterface class. Behaves as a proxy between the user interface and application's business logic.\r
+/*!\r
+ * UserInterface class. Controls the whole user interface, starting with displaying the appropriate\r
+ * views. It behaves as a proxy between the user interface and application's business logic, it connects\r
+ * the specified components together and forwards the data to the correct place. It also manages the correct\r
+ * appearance of current views on the screen.\r
+ */\r
+class WindowManager : public QObject\r
+{\r
+       Q_OBJECT\r
+\r
+public:\r
+       //! Constructor.\r
+       /*!\r
+        * Constructor of WindowManager.\r
+        */\r
+       WindowManager();\r
+       //! Destructor.\r
+       virtual ~WindowManager();\r
+\r
+signals:\r
+       //! Request current status of the room.\r
+       /*!\r
+        * Signal is emitted when there is need to check current status of room aRoom.\r
+        * \param aRoom Meetingroom which status is requested.\r
+        */\r
+       void roomStatusInfoNeeded( Room *aRoom );\r
+\r
+private slots:\r
+       //! Closes the application.\r
+       void closeApplication();\r
+       //! Updates the time.\r
+       /*!\r
+        * Forwards the signal of changed time to current view.\r
+        * \param aCurrentDateTime Current date and time.\r
+        */\r
+       void distributeDateTimeInfo( QDateTime aCurrentDateTime );\r
+       //! Updates the rooms status.\r
+       /*!\r
+        * Forwards the signal of changed status to current view.\r
+        * \param aRoom Room which status is changed.\r
+        * \param aStatus Current status of room.\r
+        * \param aTime Time when status is changed.\r
+        */\r
+       void roomStatusChanged( Room *aRoom, Room::Status aStatus, QTime aTime );\r
+       //! Displays the weekly view\r
+       void showWeeklyView();\r
+       //! Displays the screensaver (room status view)\r
+       void showRoomStatus();\r
+       //! Displays the settings view\r
+       void showSettingsView();\r
+       /*!\r
+        * Displays the meeting info dialog\r
+        * \param aMeeting Meeting to be displayd\r
+        */\r
+       void showMeetingInfo( Meeting *aMeeting );\r
+       /*!\r
+        * Displays an error message\r
+        * \param aErrorMessage Message to be displayd\r
+        */\r
+       void error( const QString &aErrorMessage );\r
+       //! Restarts the timer to launch the screensaver.\r
+       void observedEventDetected();\r
+       //! Slot for fetching meetings.\r
+       /*!\r
+        * Slot. Fetches meetings for room aRoom for currently visible week\r
+        * \param aRoom\r
+        */\r
+       void fetchMeetings( Room *aRoom );\r
+       //! Slot for fetching meetings.\r
+       /*!\r
+        * Slot. Fetches meetings for current room from date aFrom to week ahead.\r
+        * \param aFrom Date where to begin fetching\r
+        */\r
+       void fetchMeetings( QDate aFrom );\r
+       //! Slot for popping up the confirmation dialog to change the current operation mode\r
+       /*!\r
+        * Slot. Asks PopUpMessageBox to pop up a confirmation dialog.\r
+        * \param aMode The operation mode to be changed to\r
+        */\r
+       void changeModeOrdered( DeviceManager::OperationMode aMode );\r
+       //! Slot for receiving the status of the entered password\r
+       /*!\r
+        * Slot. Receives the status of the entered password and makes the DeviceManager to change the\r
+        * operation mode if the password is correct.\r
+        * \param aPasswordStatus The status of the password.\r
+        */\r
+       void passwordEntered( PasswordDialog::PasswordStatus aPasswordStatus );\r
+\r
+private:\r
+       //! Name of the application.\r
+       QString iApplicationName;\r
+       //! Pointer to the weekly view.\r
+       WeeklyViewWidget *iWeeklyView;\r
+       //! Pointer to the screensaver (room status view).\r
+       RoomStatusIndicatorWidget *iRoomStatusView;\r
+       //! Pointer to the meeting info dialog\r
+       MeetingInfoDialog *iMeetingInfo;\r
+       //! Pointer to the engine.\r
+       Engine *iEngine;\r
+       //! Timer to launch the screensaver widget\r
+       QTimer *iIdleTimeCounter;\r
+       //! Pointer to the settings view\r
+       SettingsView *iSettingsView;\r
+\r
+};\r
+\r
+#endif /*WINDOWMANAGER_H_*/\r
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644 (file)
index 0000000..9ed1c36
--- /dev/null
@@ -0,0 +1,41 @@
+#include <iostream>\r
+#include <fstream> \r
+#include <QApplication>\r
+#include <QTime>\r
+#include "WindowManager.h"\r
+\r
+using namespace std;\r
+\r
+ofstream logfile;\r
+\r
+void DebugOutputHandler( QtMsgType type, const char *msg ) {\r
+    switch( type ) {\r
+        case QtDebugMsg:\r
+            logfile << QTime::currentTime().toString().toAscii().data() << " Debug: " << msg << "\n";\r
+            logfile.flush();\r
+            break;\r
+        case QtCriticalMsg:\r
+            logfile << QTime::currentTime().toString().toAscii().data() << " Critical: " << msg << "\n";\r
+            logfile.flush();\r
+            break;\r
+        case QtWarningMsg:\r
+            logfile << QTime::currentTime().toString().toAscii().data() << " Warning: " << msg << "\n";\r
+            logfile.flush();\r
+            break;\r
+        case QtFatalMsg:\r
+            logfile << QTime::currentTime().toString().toAscii().data() <<  " Fatal: " << msg << "\n";\r
+            logfile.flush();\r
+    }\r
+}\r
+\r
+int main( int argc, char *argv[] )\r
+{\r
+       #ifndef QT_NO_DEBUG_OUTPUT\r
+       logfile.open( "/tmp/qtmeetings.log", ios::app );\r
+       qInstallMsgHandler( DebugOutputHandler );\r
+       #endif\r
+       \r
+       QApplication app( argc, argv );\r
+       WindowManager *windowManager = new WindowManager;\r
+       return app.exec();\r
+}\r
diff --git a/tests/BusinessLogic/Engine/QtMeetings.conf b/tests/BusinessLogic/Engine/QtMeetings.conf
new file mode 100644 (file)
index 0000000..c77d2c7
--- /dev/null
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration password="admin" >
+
+       <connection>
+               <!-- TEST SERVER DATA-->
+               <serverurl>192.168.0.35</serverurl>
+               <username>maemo</username>
+               <password>P@ssw0rd</password>
+               <!--
+               <serverurl>jklexch01.ixonos.com</serverurl>
+               <username>YOUR_IXONOS_USERNAME</username>
+               <password>YOUR_IXONOS_PASSWORD</password>-->
+               <!-- interval is interpreted in seconds -->
+               <refreshinterval>60</refreshinterval>
+       </connection>
+
+       <startup>
+               <powersaving enabled="true" on="08:00" off="17:00" />
+       </startup>
+
+       <display>
+               <!-- only 5 or 7 days-long weeks are supported -->
+               <schedule>
+                       <week days="5" />
+                       <day startsat="08:00" endsat="17:00" />
+               </schedule>
+               <!-- date and time format strings must be compatible with Qt's QDateTime formatting  -->
+               <dateformat>ddd dd MMM</dateformat>
+               <timeformat>hh:mm</timeformat>
+       </display>
+
+    <rooms>
+               <!-- TEST SERVER DEFAULT ROOM
+               DO NOT FODGET TO DELETE THE DEFAULT="TRUE" ATTRIBUTE OF TAURUS
+               -->
+               <room default="true">
+                       <name>TestRoom</name>
+                       <address>meetingroomtest@test.local</address>
+               </room>
+               
+               <room>
+                       <name>Pegasus</name>
+                       <address>meetingroom.pegasus_jyv@ixonos.com</address>
+               </room>
+               <room>
+                       <name>Taurus</name>
+                       <address>meetingroom.taurus_jyv@ixonos.com</address>
+               </room>
+               <room>
+                       <name>Hercules</name>
+                       <address>meetingroom.hercules@ixonos.com</address>
+               </room>
+       </rooms>
+
+       <!-- language code must be in ISO 3166-1 alpha-2 standard -->
+       <language code="EN" />
+
+</configuration>
diff --git a/tests/BusinessLogic/Engine/TestEngine.cpp b/tests/BusinessLogic/Engine/TestEngine.cpp
new file mode 100644 (file)
index 0000000..752111b
--- /dev/null
@@ -0,0 +1,91 @@
+#include <QtTest/QtTest>
+#include <QSignalSpy>
+
+#include "Engine.h"
+#include "Clock.h"
+#include "Configuration.h"
+#include "Room.h"
+#include "Meeting.h"
+#include "TestEngine.h"
+
+
+void TestEngine::initTestCase()
+{
+       iEngine = new Engine;
+       QVERIFY( iEngine != 0 );
+}
+
+void TestEngine::cleanupTestCase()
+{
+       delete iEngine;
+       iEngine = 0;
+}
+
+void TestEngine::testClock()
+{
+       ( void )iEngine->clock();
+}
+
+void TestEngine::testConfiguration()
+{
+       QCOMPARE( iEngine->configuration(), Configuration::instance() );
+}
+
+void TestEngine::testDefaultRoom()
+{
+       QCOMPARE( iEngine->defaultRoom()->equals( Configuration::instance()->defaultRoom() ), true );
+}
+
+void TestEngine::testRoomStatusInfoNeeded()
+{
+       QSignalSpy spy( iEngine, SIGNAL( roomStatusChanged( Room*, Room::Status, QTime ) ) );
+       Room* room = new Room( "foo", "bar" );
+       iEngine->roomStatusInfoNeeded( room );
+       QVERIFY( spy.count() );
+       delete room;
+}
+
+void TestEngine::testFetchMeetings()
+{
+       Room* room = new Room( "foo", "bar" );
+       iEngine->fetchMeetings( QDateTime( QDate( 2009, 4, 1 ), QTime( 0, 0, 0 ) ),
+                                       QDateTime( QDate( 2009, 4, 25 ), QTime( 0, 0, 0 ) ), room );
+       delete room;
+}
+
+void TestEngine::testCreateMeeting()
+{
+       Room* room = new Room( "foo", "bar" );
+       Meeting* meeting = new Meeting( 1234, room, QDateTime( QDate( 2009, 4, 1 ), QTime( 12, 0, 0 ) ),
+                                                 QDateTime( QDate( 2009, 4, 1 ), QTime( 12, 30, 0 ) ) );
+       iEngine->createMeeting( meeting, "foo", "bar" );
+       delete meeting;
+       delete room;
+}
+
+void TestEngine::testUpdateMeeting()
+{
+       Room* room = new Room( "foo", "bar" );
+       Meeting* meeting = new Meeting( 1234, room, QDateTime( QDate( 2009, 4, 1 ), QTime( 12, 0, 0 ) ),
+                                                 QDateTime( QDate( 2009, 4, 1 ), QTime( 12, 30, 0 ) ) );
+       iEngine->updateMeeting( meeting, "foo", "bar" );
+       delete meeting;
+       delete room;
+}
+
+void TestEngine::testDeleteMeeting()
+{
+       Room* room = new Room( "foo", "bar" );
+       Meeting* meeting = new Meeting( 1234, room, QDateTime( QDate( 2009, 4, 1 ), QTime( 12, 0, 0 ) ),
+                                                 QDateTime( QDate( 2009, 4, 1 ), QTime( 12, 30, 0 ) ) );
+       iEngine->deleteMeeting( meeting, "foo", "bar" );
+       delete meeting;
+       delete room;
+}
+
+void TestEngine::testCurrentRoomChanged()
+{
+       Room* room = new Room( "foo", "bar" );
+       iEngine->currentRoomChanged( room );
+       delete room;
+}
diff --git a/tests/BusinessLogic/Engine/TestEngine.h b/tests/BusinessLogic/Engine/TestEngine.h
new file mode 100644 (file)
index 0000000..e621ccf
--- /dev/null
@@ -0,0 +1,27 @@
+#include <QtTest/QtTest>
+
+#include "Engine.h"
+#include "Clock.h"
+#include "Configuration.h"
+#include "Room.h"
+
+class TestEngine: public QObject
+{
+       Q_OBJECT
+
+private slots:
+       void initTestCase();
+       void testClock();
+       void testConfiguration();
+       void testDefaultRoom();
+       void testRoomStatusInfoNeeded();
+       void testFetchMeetings();
+       void testCreateMeeting();
+       void testUpdateMeeting();
+       void testDeleteMeeting();
+       void testCurrentRoomChanged();
+       void cleanupTestCase();
+
+private:
+       Engine *iEngine;
+};
diff --git a/tests/BusinessLogic/Engine/TestEngineOnly.cpp b/tests/BusinessLogic/Engine/TestEngineOnly.cpp
new file mode 100644 (file)
index 0000000..d6f9b55
--- /dev/null
@@ -0,0 +1,11 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestEngine.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       TestEngine testEngine;
+       QTest::qExec( &testEngine );
+}
diff --git a/tests/BusinessLogic/Engine/TestEngineOnly.pro b/tests/BusinessLogic/Engine/TestEngineOnly.pro
new file mode 100644 (file)
index 0000000..33926c0
--- /dev/null
@@ -0,0 +1,49 @@
+QT += testlib \
+    xml \
+    network
+TEMPLATE = app
+CONFIG += qtestlib
+CONFIG += link_pkgconfig
+PKGCONFIG += libalarm
+RESOURCES += ../../../resources/BusinessLogic.qrc
+INCLUDEPATH += ../../../src/Domain/ \
+    ../../../src/Domain/Configuration/ \
+    ../../../src/BusinessLogic/ \
+    ../../../src/BusinessLogic/Utils/ \
+    ../../../src/IO/Communication/ \
+    ../../../src/IO/DeviceControl/
+HEADERS += ../../../src/Domain/Room.h \
+    ../../../src/Domain/Meeting.h \
+    ../../../src/Domain/Configuration/Configuration.h \
+    ../../../src/Domain/Configuration/ConnectionSettings.h \
+    ../../../src/Domain/Configuration/StartupSettings.h \
+    ../../../src/Domain/Configuration/DisplaySettings.h \
+    ../../../src/IO/Communication/CommunicationManager.h \
+    ../../../src/IO/Communication/Communication.h \
+    ../../../src/IO/DeviceControl/DeviceManager.h \
+    ../../../src/IO/DeviceControl/DeviceConfigurator.h \
+    ../../../src/IO/DeviceControl/HWKeyListener.h \
+    ../../../src/IO/DeviceControl/AlarmSender.h \
+    ../../../src/IO/DeviceControl/DeviceDataStorage.h \
+    ../../../src/BusinessLogic/Utils/ErrorMapper.h \
+    ../../../src/BusinessLogic/Utils/Clock.h \
+    ../../../src/BusinessLogic/Engine.h \
+    TestEngine.h
+SOURCES += ../../../src/Domain/Room.cpp \
+    ../../../src/Domain/Meeting.cpp \
+    ../../../src/Domain/Configuration/Configuration.cpp \
+    ../../../src/Domain/Configuration/ConnectionSettings.cpp \
+    ../../../src/Domain/Configuration/StartupSettings.cpp \
+    ../../../src/Domain/Configuration/DisplaySettings.cpp \
+    ../../../src/IO/Communication/CommunicationManager.cpp \
+    ../../../src/IO/Communication/Communication.cpp \
+    ../../../src/IO/DeviceControl/DeviceManager.cpp \
+    ../../../src/IO/DeviceControl/DeviceConfigurator.cpp \
+    ../../../src/IO/DeviceControl/HWKeyListener.cpp \
+    ../../../src/IO/DeviceControl/AlarmSender.cpp \
+    ../../../src/IO/DeviceControl/DeviceDataStorage.cpp \
+    ../../../src/BusinessLogic/Utils/ErrorMapper.cpp \
+    ../../../src/BusinessLogic/Utils/Clock.cpp \
+    ../../../src/BusinessLogic/Engine.cpp \
+    TestEngine.cpp \
+    TestEngineOnly.cpp
diff --git a/tests/BusinessLogic/Utils/Clock/TestClock.cpp b/tests/BusinessLogic/Utils/Clock/TestClock.cpp
new file mode 100644 (file)
index 0000000..2424a1a
--- /dev/null
@@ -0,0 +1,42 @@
+#include <QtTest/QtTest>
+#include "Clock.h"
+#include <QSignalSpy>
+#include "TestClock.h"
+
+void TestClock::initTestCase()
+{
+       iClock = new Clock();
+       QVERIFY( iClock != 0 );
+       QSignalSpy spy( iClock, SIGNAL( tick( QDateTime ) ) );
+       QVERIFY( spy.isValid() );
+       QTest::qWait( 5000 );
+       QVERIFY( spy.count() > 0 );
+       QList<QVariant> args = spy.takeFirst();
+       QVERIFY( args.at( 0 ).type() == QVariant::DateTime );
+}
+
+void TestClock::cleanupTestCase()
+{
+       delete iClock;
+       iClock = 0;
+}
+
+void TestClock::testDatetime()
+{
+       QCOMPARE( iClock->datetime(), QDateTime::currentDateTime() );
+}
+
+void TestClock::testDate()
+{
+       QCOMPARE( iClock->today(), QDateTime::currentDateTime().date() );
+}
+
+void TestClock::testTime()
+{
+       QCOMPARE( iClock->time(), QDateTime::currentDateTime().time() );
+}
+
+void TestClock::testSynchronizeDatetime()
+{
+       iClock->syncronizeDateTime();
+}
diff --git a/tests/BusinessLogic/Utils/Clock/TestClock.h b/tests/BusinessLogic/Utils/Clock/TestClock.h
new file mode 100644 (file)
index 0000000..6fdd8fd
--- /dev/null
@@ -0,0 +1,18 @@
+#include "Clock.h"
+
+class TestClock: public QObject
+{
+       Q_OBJECT
+
+private slots:
+       void initTestCase();
+       void testDatetime();
+       void testDate();
+       void testTime();
+       void testSynchronizeDatetime();
+       void cleanupTestCase();
+
+private:
+       Clock *iClock;
+
+};
diff --git a/tests/BusinessLogic/Utils/Clock/TestClockOnly.cpp b/tests/BusinessLogic/Utils/Clock/TestClockOnly.cpp
new file mode 100644 (file)
index 0000000..4173fe5
--- /dev/null
@@ -0,0 +1,11 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestClock.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       TestClock testClock;
+       QTest::qExec( &testClock );
+}
diff --git a/tests/BusinessLogic/Utils/Clock/TestClockOnly.pro b/tests/BusinessLogic/Utils/Clock/TestClockOnly.pro
new file mode 100644 (file)
index 0000000..de69d5f
--- /dev/null
@@ -0,0 +1,9 @@
+QT += testlib
+TEMPLATE = app
+CONFIG += qtestlib
+INCLUDEPATH += ../../../../src/BusinessLogic/Utils/
+HEADERS += ../../../../src/BusinessLogic/Utils/Clock.h \
+    TestClock.h
+SOURCES += ../../../../src/BusinessLogic/Utils/Clock.cpp \
+    TestClock.cpp \
+    TestClockOnly.cpp
diff --git a/tests/BusinessLogic/Utils/ErrorMapper/TestErrorMapper.cpp b/tests/BusinessLogic/Utils/ErrorMapper/TestErrorMapper.cpp
new file mode 100644 (file)
index 0000000..aa12175
--- /dev/null
@@ -0,0 +1,18 @@
+#include <QtTest/QtTest>
+#include "ErrorMapper.h"
+#include "TestErrorMapper.h"
+
+void TestErrorMapper::initTestCase()
+{
+}
+
+void TestErrorMapper::cleanupTestCase()
+{
+}
+
+void TestErrorMapper::testCodeToString()
+{
+       QCOMPARE( QString::compare( ErrorMapper::codeToString( 0 ), QString( "Not really an error. Everything went just fine." ) ), 0 );
+       QCOMPARE( QString::compare( ErrorMapper::codeToString( 666 ), QString( "For unit test purposes." ) ), 0 );
+       QCOMPARE( QString::compare( ErrorMapper::codeToString( -1 ), QString( "" ) ), 0 );
+}
diff --git a/tests/BusinessLogic/Utils/ErrorMapper/TestErrorMapper.h b/tests/BusinessLogic/Utils/ErrorMapper/TestErrorMapper.h
new file mode 100644 (file)
index 0000000..c22cdef
--- /dev/null
@@ -0,0 +1,12 @@
+#include <QObject>
+
+class TestErrorMapper: public QObject
+{
+       Q_OBJECT
+
+private slots:
+       void initTestCase();
+       void testCodeToString();
+       void cleanupTestCase();
+
+};
diff --git a/tests/BusinessLogic/Utils/ErrorMapper/TestErrorMapperOnly.cpp b/tests/BusinessLogic/Utils/ErrorMapper/TestErrorMapperOnly.cpp
new file mode 100644 (file)
index 0000000..2e7a8a5
--- /dev/null
@@ -0,0 +1,11 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestErrorMapper.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       TestErrorMapper testErrorMapper;
+       QTest::qExec( &testErrorMapper );
+}
diff --git a/tests/BusinessLogic/Utils/ErrorMapper/TestErrorMapperOnly.pro b/tests/BusinessLogic/Utils/ErrorMapper/TestErrorMapperOnly.pro
new file mode 100644 (file)
index 0000000..9f02586
--- /dev/null
@@ -0,0 +1,11 @@
+QT += testlib
+QT += xml
+TEMPLATE = app
+CONFIG += qtestlib
+RESOURCES = ../../../../resources/BusinessLogic.qrc
+INCLUDEPATH += ../../../../src/BusinessLogic/Utils/
+HEADERS += ../../../../src/BusinessLogic/Utils/ErrorMapper.h \
+    TestErrorMapper.h
+SOURCES += ../../../../src/BusinessLogic/Utils/ErrorMapper.cpp \
+    TestErrorMapper.cpp \
+    TestErrorMapperOnly.cpp
diff --git a/tests/Domain/Configuration/Configuration/QtMeetings.conf b/tests/Domain/Configuration/Configuration/QtMeetings.conf
new file mode 100644 (file)
index 0000000..5025781
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration password="admin" >
+
+       <connection>
+               <serverurl>jklexch01.ixonos.com</serverurl>
+               <username>username</username>
+               <password>password</password>-->
+               <!-- interval is interpreted in seconds -->
+               <refreshinterval>65</refreshinterval>
+       </connection>
+
+       <startup>
+               <powersaving enabled="false" on="08:00" off="17:00" />
+       </startup>
+
+       <display>
+               <!-- only 5 or 7 days-long weeks are supported -->
+               <schedule>
+                       <week days="5" />
+                       <day startsat="08:00" endsat="17:00" />
+               </schedule>
+               <!-- date and time format strings must be compatible with Qt's QDateTime formatting  -->
+               <dateformat>ddd dd MMM</dateformat>
+               <timeformat>hh:mm</timeformat>
+       </display>
+
+    <rooms>
+               <room>
+                       <name>Pegasus</name>
+                       <address>meetingroom.pegasus_jyv@ixonos.com</address>
+               </room>
+               <room default="true">
+                       <name>Taurus</name>
+                       <address>meetingroom.taurus_jyv@ixonos.com</address>
+               </room>
+               <room>
+                       <name>Hercules</name>
+                       <address>meetingroom.hercules@ixonos.com</address>
+               </room>
+       </rooms>
+
+       <!-- language code must be in ISO 3166-1 alpha-2 standard -->
+       <language code="EN" />
+
+</configuration>
diff --git a/tests/Domain/Configuration/Configuration/TestConfiguration.cpp b/tests/Domain/Configuration/Configuration/TestConfiguration.cpp
new file mode 100644 (file)
index 0000000..130fe91
--- /dev/null
@@ -0,0 +1,165 @@
+#include <QtTest/QtTest>
+#include "Configuration.h"
+#include "ConnectionSettings.h"
+#include "DisplaySettings.h"
+#include "StartupSettings.h"
+#include "Room.h"
+#include "TestConfiguration.h"
+
+const QString sAdminPw = "admin";
+const QString sUsername = "username";
+const QString sServerPw = "password"; 
+const QString sServerUrl = "jklexch01.ixonos.com";
+const unsigned int sRefreshInterval = 30;
+const DisplaySettings::DateFormat sDateFormat = DisplaySettings::LongDateFormat;
+const DisplaySettings::TimeFormat sTimeFormat = DisplaySettings::TwelveHoursTimeFormat;
+const DisplaySettings::DaysInSchedule sDaysInSchedule = DisplaySettings::WholeWeekInSchedule;
+const QTime sDayStartsAt = QTime(6,0);
+const QTime sDayEndsAt = QTime(18,0);
+const int sScreensaver = 1;
+
+const bool sIsPowersavingEnabled = false;
+const QTime sTurnOnAt = QTime(5,45);
+const QTime sTurnOffAt = QTime(18,15);
+
+
+
+void TestConfiguration::initTestCase()
+{
+       iConf = Configuration::instance();
+       QVERIFY( iConf != 0 );
+
+       // Set values to empty configuration
+       QList<Room*> testrooms;
+       testrooms.append( new Room( "Taurus", "meetingroom.taurus_jyv@ixonos.com" ) );
+       testrooms.append( new Room( "Pegasus", "meetingroom.pegasus_jyv@ixonos.com" ) );
+       testrooms.append( new Room( "Hercules", "meetingroom.hercules@ixonos.com" ) );
+       iConf->setRooms(testrooms);
+       iConf->setAdminPassword(sAdminPw);
+
+       // connection
+       iConf->connectionSettings()->setServerUrl(sServerUrl);
+       iConf->connectionSettings()->setUsername(sUsername);
+       iConf->connectionSettings()->setPassword(sServerPw);
+       iConf->connectionSettings()->setRefreshInterval(sRefreshInterval);
+       
+       // display
+       iConf->displaySettings()->setDateFormat(sDateFormat);
+       iConf->displaySettings()->setTimeFormat(sTimeFormat);
+       iConf->displaySettings()->setDayStartsAt(sDayStartsAt);
+       iConf->displaySettings()->setDayEndsAt(sDayEndsAt);
+       iConf->displaySettings()->setDaysInSchedule(sDaysInSchedule);
+       iConf->displaySettings()->setScreensaver(sScreensaver);
+       
+       // startup
+       iConf->startupSettings()->setPowersavingEnabled(sIsPowersavingEnabled);
+       iConf->startupSettings()->setTurnOnAt(sTurnOnAt);
+       iConf->startupSettings()->setTurnOffAt(sTurnOffAt);
+}
+
+void TestConfiguration::cleanupTestCase()
+{
+       delete iConf;
+       iConf = NULL;
+}
+
+void TestConfiguration::init()
+{
+}
+
+void TestConfiguration::cleanup()
+{
+}
+
+void TestConfiguration::testInstance()
+{
+       QCOMPARE( iConf, Configuration::instance() );
+}
+
+void TestConfiguration::testSave()
+{
+       // Just check there is no crash
+       // The following testcases make sure the settings are saved correctly
+       iConf->save();
+/*     
+       // delete old configuration 
+       delete iConf;
+       iConf = NULL;
+       // ...and create new instance
+       iConf = Configuration::instance();
+       QVERIFY( iConf != 0 ); */
+}
+
+
+void TestConfiguration::testDefaultRoom()
+{
+       
+       Room* room = iConf->defaultRoom();
+       QVERIFY( room != 0 );
+       QCOMPARE( room->name(), QString("Taurus") );
+       QCOMPARE( room->address(), QString("meetingroom.taurus_jyv@ixonos.com") );
+}
+
+void TestConfiguration::testConnectionSettings()
+{
+       ConnectionSettings* conn = iConf->connectionSettings();
+       QVERIFY( conn != 0 );
+       QCOMPARE( conn->serverUrl().toString(), sServerUrl );
+       QCOMPARE( conn->username(), sUsername );
+       QCOMPARE( conn->password(), sServerPw );
+       QCOMPARE( conn->refreshInterval(), sRefreshInterval );
+}
+
+void TestConfiguration::testLanguageCode()
+{
+       QCOMPARE( iConf->languageCode(), QString( "EN" ) );
+}
+
+void TestConfiguration::testRooms()
+{
+       QList<Room*> testrooms;
+       testrooms.append( new Room( "Taurus", "meetingroom.taurus_jyv@ixonos.com" ) );
+       testrooms.append( new Room( "Pegasus", "meetingroom.pegasus_jyv@ixonos.com" ) );
+       testrooms.append( new Room( "Hercules", "meetingroom.hercules@ixonos.com" ) );
+       
+       QList<Room*> rooms = iConf->rooms();
+       QVERIFY( rooms.count() == 3 );
+       QCOMPARE( rooms[0], iConf->defaultRoom() );
+       for ( int i = 0; i < rooms.count(); i++ )
+       {
+               Room* room = rooms[i];
+               Room* testroom = testrooms[i];
+               QCOMPARE( room->name(), testroom->name() );
+               QCOMPARE( room->address(), testroom->address() );
+       }
+}
+
+void TestConfiguration::testStartupSettings()
+{
+       StartupSettings *settings = iConf->startupSettings();
+
+       QVERIFY( settings->isPowersavingEnabled() == sIsPowersavingEnabled );
+       QCOMPARE( settings->turnOnAt(), sTurnOnAt );
+       QCOMPARE( settings->turnOffAt(), sTurnOffAt );
+}
+
+void TestConfiguration::testDisplaySettings()
+{
+       DisplaySettings *settings = iConf->displaySettings();
+       
+       QVERIFY( settings->daysInSchedule() == sDaysInSchedule );
+       QCOMPARE( settings->dayStartsAt(), sDayStartsAt );
+       QCOMPARE( settings->dayEndsAt(), sDayEndsAt );
+       QCOMPARE( settings->dateFormat(), QString( "dddd d MMMM yyyy" ) );
+       QCOMPARE( settings->timeFormat(), QString( "hh:mm ap" ) );
+}
+
+void TestConfiguration::testAdminPassword()
+{
+       QCryptographicHash *hash = new QCryptographicHash( QCryptographicHash::Md5 );
+       hash->addData( sAdminPw.toUtf8() );
+       QByteArray password = hash->result();
+       delete hash;
+
+       QCOMPARE( iConf->adminPassword(), QString( password ) );
+}
diff --git a/tests/Domain/Configuration/Configuration/TestConfiguration.h b/tests/Domain/Configuration/Configuration/TestConfiguration.h
new file mode 100644 (file)
index 0000000..c056cb8
--- /dev/null
@@ -0,0 +1,29 @@
+#include <QtTest/QtTest>
+#include "Configuration.h"
+#include "ConnectionSettings.h"
+#include "DisplaySettings.h"
+#include "StartupSettings.h"
+#include "Room.h"
+
+class TestConfiguration: public QObject
+{
+       Q_OBJECT
+
+private slots:
+       void initTestCase();
+       void init();
+       void cleanup();
+       void testInstance();
+       void testSave(); 
+       void testConnectionSettings();
+       void testDefaultRoom();
+       void testLanguageCode();
+       void testRooms();
+       void testStartupSettings();
+       void testDisplaySettings();
+       void testAdminPassword(); 
+       void cleanupTestCase();
+
+private:
+       Configuration* iConf;
+};
diff --git a/tests/Domain/Configuration/Configuration/TestConfigurationOnly.cpp b/tests/Domain/Configuration/Configuration/TestConfigurationOnly.cpp
new file mode 100644 (file)
index 0000000..4b903cb
--- /dev/null
@@ -0,0 +1,11 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestConfiguration.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       TestConfiguration testConfiguration;
+       QTest::qExec( &testConfiguration );
+}
diff --git a/tests/Domain/Configuration/Configuration/TestConfigurationOnly.pro b/tests/Domain/Configuration/Configuration/TestConfigurationOnly.pro
new file mode 100644 (file)
index 0000000..c35ef6b
--- /dev/null
@@ -0,0 +1,18 @@
+QT += testlib xml
+TEMPLATE = app
+CONFIG += qtestlib
+INCLUDEPATH += ../../../../src/Domain/ \
+    ../../../../src/Domain/Configuration/
+HEADERS += ../../../../src/Domain/Configuration/Configuration.h \
+    ../../../../src/Domain/Configuration/ConnectionSettings.h \
+    ../../../../src/Domain/Configuration/DisplaySettings.h \
+    ../../../../src/Domain/Configuration/StartupSettings.h \
+    ../../../../src/Domain/Room.h \
+    TestConfiguration.h
+SOURCES += ../../../../src/Domain/Configuration/Configuration.cpp \
+    ../../../../src/Domain/Configuration/ConnectionSettings.cpp \
+    ../../../../src/Domain/Configuration/DisplaySettings.cpp \
+    ../../../../src/Domain/Configuration/StartupSettings.cpp \
+    ../../../../src/Domain/Room.cpp  \
+    TestConfiguration.cpp \
+    TestConfigurationOnly.cpp
diff --git a/tests/Domain/Configuration/ConnectionSettings/TestConnectionSettings.cpp b/tests/Domain/Configuration/ConnectionSettings/TestConnectionSettings.cpp
new file mode 100644 (file)
index 0000000..745ce01
--- /dev/null
@@ -0,0 +1,50 @@
+#include <QtTest/QtTest>
+#include "ConnectionSettings.h"
+#include "TestConnectionSettings.h"
+
+static const QString URL = "http://this.is.just/a_test_url/for unit test";
+static const QString USERNAME = "Username";
+static const QString PASSWORD = "Password";
+static const unsigned int INTERVAL = 60;
+
+void TestConnectionSettings::initTestCase()
+{
+       iConnection = new ConnectionSettings( QUrl( URL ), USERNAME, PASSWORD, INTERVAL );
+       QVERIFY( iConnection != 0 );
+}
+
+void TestConnectionSettings::cleanupTestCase()
+{
+       delete iConnection;
+       iConnection = NULL;
+}
+
+void TestConnectionSettings::init()
+{
+       //qDebug("Debug line");
+}
+
+void TestConnectionSettings::cleanup()
+{
+       //nothing to do
+}
+
+void TestConnectionSettings::testServerUrl()
+{
+       QCOMPARE( iConnection->serverUrl().toString(), URL );
+}
+
+void TestConnectionSettings::testUsername()
+{
+       QCOMPARE( iConnection->username(), USERNAME );
+}
+
+void TestConnectionSettings::testPassword()
+{
+       QCOMPARE( iConnection->password(), PASSWORD );
+}
+
+void TestConnectionSettings::testInterval()
+{
+       QCOMPARE( iConnection->refreshInterval(), INTERVAL );
+}
diff --git a/tests/Domain/Configuration/ConnectionSettings/TestConnectionSettings.h b/tests/Domain/Configuration/ConnectionSettings/TestConnectionSettings.h
new file mode 100644 (file)
index 0000000..e641b66
--- /dev/null
@@ -0,0 +1,50 @@
+#include <QtTest/QtTest>
+#include "ConnectionSettings.h"
+
+class TestConnectionSettings: public QObject
+{
+       Q_OBJECT
+
+private slots:
+       /*!
+        * \function initTestCase is executed before testcase
+        */
+       void initTestCase();
+       /*!
+        * \function init is executed before individual test
+        */
+       void init();
+       /*!
+        *
+        * \function cleanup is executed after individual test
+        */
+       void cleanup();
+
+       /*!
+        * test for server url
+        */
+       void testServerUrl();
+       /*!
+        * test for username
+        */
+       void testUsername();
+
+       /*!
+        * test for password
+        */
+       void testPassword();
+
+       /*!
+         * test for refresh interval
+         */
+       void testInterval();
+
+       /*!
+        * \function cleanupTestCase is executed after testcase
+        */
+       void cleanupTestCase();
+
+private:
+       ConnectionSettings *iConnection;
+
+};
diff --git a/tests/Domain/Configuration/ConnectionSettings/TestConnectionSettingsOnly.cpp b/tests/Domain/Configuration/ConnectionSettings/TestConnectionSettingsOnly.cpp
new file mode 100644 (file)
index 0000000..aa132d7
--- /dev/null
@@ -0,0 +1,11 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestConnectionSettings.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       TestConnectionSettings testConnectionSettings;
+       QTest::qExec( &testConnectionSettings );
+}
diff --git a/tests/Domain/Configuration/ConnectionSettings/TestConnectionSettingsOnly.pro b/tests/Domain/Configuration/ConnectionSettings/TestConnectionSettingsOnly.pro
new file mode 100644 (file)
index 0000000..a845b2a
--- /dev/null
@@ -0,0 +1,9 @@
+QT += testlib
+TEMPLATE = app
+CONFIG += qtestlib
+INCLUDEPATH += ../../../../src/Domain/Configuration/
+HEADERS += ../../../../src/Domain/Configuration/ConnectionSettings.h \
+    TestConnectionSettings.h
+SOURCES += ../../../../src/Domain/Configuration/ConnectionSettings.cpp \
+    TestConnectionSettings.cpp \
+    TestConnectionSettingsOnly.cpp
diff --git a/tests/Domain/Configuration/DisplaySettings/TestDisplaySettings.cpp b/tests/Domain/Configuration/DisplaySettings/TestDisplaySettings.cpp
new file mode 100644 (file)
index 0000000..ca5c090
--- /dev/null
@@ -0,0 +1,72 @@
+#include <QtTest/QtTest>
+#include <QDateTime>
+#include "DisplaySettings.h"
+#include "TestDisplaySettings.h"
+
+const QTime TIME_0800 = QTime( 8, 00 );
+const QTime TIME_0845 = QTime( 8, 45 );
+const QTime TIME_1700 = QTime( 17, 00 );
+const QTime TIME_1710 = QTime( 17, 10 );
+
+const QString DF_LONG = "dddd d MMMM yyyy";
+const QString DF_SHORT = "ddd d MMM";
+
+const QString TF_12 = "hh:mm ap";
+const QString TF_24 = "hh:mm";
+
+void TestDisplaySettings::initTestCase()
+{
+       iSettings_Long_12_7_800_1700 = new DisplaySettings( DisplaySettings::LongDateFormat, DisplaySettings::TwelveHoursTimeFormat, DisplaySettings::WholeWeekInSchedule, TIME_0800, TIME_1700 );
+       iSettings_Short_24_5_845_1710 = new DisplaySettings( DisplaySettings::ShortDateFormat, DisplaySettings::TwentyFourHoursTimeFormat, DisplaySettings::WeekdaysInSchedule, TIME_0845, TIME_1710 );
+       QVERIFY( iSettings_Long_12_7_800_1700 != 0 );
+       QVERIFY( iSettings_Short_24_5_845_1710 != 0 );
+}
+
+void TestDisplaySettings::cleanupTestCase()
+{
+       delete iSettings_Long_12_7_800_1700;
+       iSettings_Long_12_7_800_1700 = 0;
+
+       delete iSettings_Short_24_5_845_1710;
+       iSettings_Short_24_5_845_1710 = 0;
+}
+
+void TestDisplaySettings::init()
+{
+       //qDebug("Debug line");
+}
+
+void TestDisplaySettings::cleanup()
+{
+       //nothing to do
+}
+
+void TestDisplaySettings::testDateFormat()
+{
+       QCOMPARE( iSettings_Long_12_7_800_1700->dateFormat(), DF_LONG );
+       QCOMPARE( iSettings_Short_24_5_845_1710->dateFormat(), DF_SHORT );
+}
+
+void TestDisplaySettings::testTimeFormat()
+{
+       QCOMPARE( iSettings_Long_12_7_800_1700->timeFormat(), TF_12 );
+       QCOMPARE( iSettings_Short_24_5_845_1710->timeFormat(), TF_24 );
+}
+
+void TestDisplaySettings::testDaysInSchedule()
+{
+       QCOMPARE( iSettings_Long_12_7_800_1700->daysInSchedule(), DisplaySettings::WholeWeekInSchedule );
+       QCOMPARE( iSettings_Short_24_5_845_1710->daysInSchedule(), DisplaySettings::WeekdaysInSchedule );
+}
+
+void TestDisplaySettings::testDayStartsAt()
+{
+       QCOMPARE( iSettings_Long_12_7_800_1700->dayStartsAt(), TIME_0800 );
+       QCOMPARE( iSettings_Short_24_5_845_1710->dayStartsAt(), TIME_0845 );
+}
+
+void TestDisplaySettings::tetsDayEndsAt()
+{
+       QCOMPARE( iSettings_Long_12_7_800_1700->dayEndsAt(), TIME_1700 );
+       QCOMPARE( iSettings_Short_24_5_845_1710->dayEndsAt(), TIME_1710 );
+}
diff --git a/tests/Domain/Configuration/DisplaySettings/TestDisplaySettings.h b/tests/Domain/Configuration/DisplaySettings/TestDisplaySettings.h
new file mode 100644 (file)
index 0000000..8c5d6ba
--- /dev/null
@@ -0,0 +1,25 @@
+#include <QtTest/QtTest>
+#include <QDateTime>
+#include "DisplaySettings.h"
+
+class TestDisplaySettings: public QObject
+{
+       Q_OBJECT
+
+private slots:
+       void initTestCase();
+       void cleanupTestCase();
+       void init();
+       void cleanup();
+
+       void testDateFormat();
+       void testTimeFormat();
+       void testDaysInSchedule();
+       void testDayStartsAt();
+       void tetsDayEndsAt();
+
+private:
+       DisplaySettings *iSettings_Long_12_7_800_1700;
+       DisplaySettings *iSettings_Short_24_5_845_1710;
+
+};
diff --git a/tests/Domain/Configuration/DisplaySettings/TestDisplaySettingsOnly.cpp b/tests/Domain/Configuration/DisplaySettings/TestDisplaySettingsOnly.cpp
new file mode 100644 (file)
index 0000000..19f4cc2
--- /dev/null
@@ -0,0 +1,11 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestDisplaySettings.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       TestDisplaySettings testDisplaySettings;
+       QTest::qExec( &testDisplaySettings );
+}
diff --git a/tests/Domain/Configuration/DisplaySettings/TestDisplaySettingsOnly.pro b/tests/Domain/Configuration/DisplaySettings/TestDisplaySettingsOnly.pro
new file mode 100644 (file)
index 0000000..4f0d68d
--- /dev/null
@@ -0,0 +1,9 @@
+QT += testlib
+TEMPLATE = app
+CONFIG += qtestlib
+INCLUDEPATH += ../../../../src/Domain/Configuration/
+HEADERS += ../../../../src/Domain/Configuration/DisplaySettings.h \
+    TestDisplaySettings.h
+SOURCES += ../../../../src/Domain/Configuration/DisplaySettings.cpp \
+    TestDisplaySettings.cpp \
+    TestDisplaySettingsOnly.cpp
diff --git a/tests/Domain/Configuration/StartupSettings/TestStartupSettings.cpp b/tests/Domain/Configuration/StartupSettings/TestStartupSettings.cpp
new file mode 100644 (file)
index 0000000..fff16b9
--- /dev/null
@@ -0,0 +1,55 @@
+#include <QtTest/QtTest>
+#include <QDateTime>
+#include "StartupSettings.h"
+#include "TestStartupSettings.h"
+
+const QTime TIME_0800 = QTime( 8, 00 );
+const QTime TIME_0845 = QTime( 8, 45 );
+const QTime TIME_1700 = QTime( 17, 00 );
+const QTime TIME_1710 = QTime( 17, 10 );
+
+void TestStartupSettings::initTestCase()
+{
+       iSettings_f_800_1700 = new StartupSettings( false, TIME_0800, TIME_1700 );
+       iSettings_t_845_1710 = new StartupSettings( true, TIME_0845, TIME_1710 );
+
+       QVERIFY( iSettings_f_800_1700 != 0 );
+       QVERIFY( iSettings_t_845_1710 != 0 );
+}
+
+void TestStartupSettings::cleanupTestCase()
+{
+       delete iSettings_f_800_1700;
+       iSettings_f_800_1700 = 0;
+
+       delete iSettings_t_845_1710;
+       iSettings_t_845_1710 = 0;
+}
+
+void TestStartupSettings::init()
+{
+       //qDebug("Debug line");
+}
+
+void TestStartupSettings::cleanup()
+{
+       //nothing to do
+}
+
+void TestStartupSettings::testIsPowersavingEnabled()
+{
+       QCOMPARE( iSettings_f_800_1700->isPowersavingEnabled(), false );
+       QCOMPARE( iSettings_t_845_1710->isPowersavingEnabled(), true );
+}
+
+void TestStartupSettings::testTurnOnAt()
+{
+       QCOMPARE( iSettings_f_800_1700->turnOnAt(), TIME_0800 );
+       QCOMPARE( iSettings_t_845_1710->turnOnAt(), TIME_0845 );
+}
+
+void TestStartupSettings::testTurnOffAt()
+{
+       QCOMPARE( iSettings_f_800_1700->turnOffAt(), TIME_1700 );
+       QCOMPARE( iSettings_t_845_1710->turnOffAt(), TIME_1710 );
+}
diff --git a/tests/Domain/Configuration/StartupSettings/TestStartupSettings.h b/tests/Domain/Configuration/StartupSettings/TestStartupSettings.h
new file mode 100644 (file)
index 0000000..244c63e
--- /dev/null
@@ -0,0 +1,23 @@
+#include <QtTest/QtTest>
+#include "StartupSettings.h"
+#include <QDateTime>
+
+class TestStartupSettings: public QObject
+{
+       Q_OBJECT
+
+private slots:
+       void initTestCase();
+       void init();
+       void cleanupTestCase();
+       void cleanup();
+
+       void testIsPowersavingEnabled();
+       void testTurnOnAt();
+       void testTurnOffAt();
+
+private:
+       StartupSettings *iSettings_f_800_1700;
+       StartupSettings *iSettings_t_845_1710;
+
+};
diff --git a/tests/Domain/Configuration/StartupSettings/TestStartupSettingsOnly.cpp b/tests/Domain/Configuration/StartupSettings/TestStartupSettingsOnly.cpp
new file mode 100644 (file)
index 0000000..1d1d638
--- /dev/null
@@ -0,0 +1,11 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestStartupSettings.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       TestStartupSettings testStartupSettings;
+       QTest::qExec( &testStartupSettings );
+}
diff --git a/tests/Domain/Configuration/StartupSettings/TestStartupSettingsOnly.pro b/tests/Domain/Configuration/StartupSettings/TestStartupSettingsOnly.pro
new file mode 100644 (file)
index 0000000..39264fc
--- /dev/null
@@ -0,0 +1,9 @@
+QT += testlib
+TEMPLATE = app
+CONFIG += qtestlib
+INCLUDEPATH += ../../../../src/Domain/Configuration/
+HEADERS += ../../../../src/Domain/Configuration/StartupSettings.h \
+    TestStartupSettings.h
+SOURCES += ../../../../src/Domain/Configuration/StartupSettings.cpp \
+    TestStartupSettings.cpp \
+    TestStartupSettingsOnly.cpp
diff --git a/tests/Domain/Meeting/TestMeeting.cpp b/tests/Domain/Meeting/TestMeeting.cpp
new file mode 100644 (file)
index 0000000..e38434b
--- /dev/null
@@ -0,0 +1,184 @@
+#include <QtTest/QtTest>
+#include "Meeting.h"
+#include "Room.h"
+#include "TestMeeting.h"
+
+void TestMeeting::initTestCase()
+{
+       iPrimaryId1 = 5;
+       iPrimaryId2 = 0xa6c8eef1;
+       iSecondaryId1 = 0;
+       iSecondaryId2 = 0xFFFF0005;
+
+       iRoom = new Room( "Pegasus", "meetingroom.pegasus_jyv@ixonos.com" );
+       QVERIFY( iRoom != 0 );
+
+       iOrganizer1Name = "Test Organizer";
+       iOrganizer1EMail = "test.organizer@company.url";
+       iOrganizer2EMail = "Another Organizer";
+       iOrganizer2Name = "another.organizer@company.url";
+
+       iStartsAt1 = QDateTime( QDate( 2007, 3, 13 ), QTime( 13, 0, 0 ) );
+       iStartsAt2 = QDateTime( QDate( 2007, 3, 14 ), QTime( 13, 0, 0 ) );
+
+       iEndsAt1 = QDateTime( QDate( 2007, 3, 13 ), QTime( 14, 0, 0 ) );
+       iEndsAt2 = QDateTime( QDate( 2007, 3, 14 ), QTime( 14, 0, 0 ) );
+
+       iSubject1 = "Test subject";
+       iSubject2 = "Another subject";
+
+       iDescription1 = "This is a description. This is actually a plain text description, not as is was important at all.";
+       iDescription2 = "<p>This is a description. This is actually a <b>HTML<//b> text description, <i>not as is was important at all.<//i><//p>";
+
+       iMeeting1 = new Meeting( iPrimaryId1, iRoom, iStartsAt1, iEndsAt1, iOrganizer1Name, iOrganizer1EMail, iSubject1 );
+       QVERIFY( iMeeting1 != 0 );
+
+       iMeeting2 = new Meeting( iPrimaryId1, iRoom, iStartsAt1, iEndsAt1, "", "", iSubject1, iDescription2 );
+       QVERIFY( iMeeting2 != 0 );
+}
+
+void TestMeeting::cleanupTestCase()
+{
+       delete iMeeting1;
+       iMeeting1 = NULL;
+       delete iMeeting2;
+       iMeeting2 = NULL;
+       delete iRoom;
+       iRoom = NULL;
+}
+
+void TestMeeting::init()
+{
+       //qDebug("Debug line");
+}
+
+void TestMeeting::cleanup()
+{
+       //nothing to do
+}
+
+void TestMeeting::testPrimaryId()
+{
+       QCOMPARE( iMeeting1->primaryId(), iPrimaryId1 );
+       QCOMPARE( iMeeting2->primaryId(), iPrimaryId1 );
+}
+
+void TestMeeting::testSecondaryId()
+{
+       iMeeting1->setSecondaryId( iSecondaryId1 );
+       QCOMPARE( iMeeting1->secondaryId(), iSecondaryId1 );
+       QCOMPARE( iMeeting2->secondaryId(), 0 );
+}
+
+void TestMeeting::testGetAndSetOrganizer()
+{
+       QCOMPARE( iMeeting2->organizer(), QString( "" ) );
+
+       iMeeting2->setOrganizer( iOrganizer2Name, "" );
+       QCOMPARE( iMeeting2->organizer(), iOrganizer2Name );
+
+       iMeeting2->setOrganizer( "", iOrganizer2EMail );
+       QCOMPARE( iMeeting2->organizer(), iOrganizer2EMail );
+
+       iMeeting2->setOrganizer( iOrganizer2Name, iOrganizer2EMail );
+       QCOMPARE( iMeeting2->organizer(), QString( "%1 <%2>" ).arg( iOrganizer2Name ).arg( iOrganizer2EMail ) );
+}
+
+void TestMeeting::testStartsAt()
+{
+       QCOMPARE( iMeeting1->startsAt(), iStartsAt1 );
+}
+
+void TestMeeting::testEndsAt()
+{
+       QCOMPARE( iMeeting1->endsAt(), iEndsAt1 );
+}
+
+void TestMeeting::testSubject()
+{
+       QCOMPARE( iMeeting1->subject(), iSubject1 );
+}
+
+void TestMeeting::testDescription()
+{
+       QCOMPARE( iMeeting1->description(), QString( "" ) );
+       QCOMPARE( iMeeting2->description(), iDescription2 );
+}
+
+void TestMeeting::testDetailsAvailable()
+{
+       QCOMPARE( iMeeting1->detailsAvailable(), true );
+       QCOMPARE( iMeeting2->detailsAvailable(), false );
+}
+
+void TestMeeting::testSetSecondaryId()
+{
+       iMeeting1->setSecondaryId( -1 );
+       QCOMPARE( iMeeting1->secondaryId(), -1 );
+
+       iMeeting1->setSecondaryId( iSecondaryId1 );
+       QCOMPARE( iMeeting1->secondaryId(), iSecondaryId1 );
+
+       iMeeting2->setSecondaryId( iSecondaryId2 );
+       QCOMPARE( iMeeting2->secondaryId(), iSecondaryId2 );
+}
+
+void TestMeeting::testSetStartsAt()
+{
+       iMeeting1->setStartsAt( iStartsAt2 );
+       QCOMPARE( iMeeting1->startsAt(), iStartsAt2 );
+
+       iMeeting1->setStartsAt( iStartsAt1 );
+       QCOMPARE( iMeeting1->startsAt(), iStartsAt1 );
+}
+
+void TestMeeting::testSetEndsAt()
+{
+       iMeeting1->setEndsAt( iEndsAt2 );
+       QCOMPARE( iMeeting1->endsAt(), iEndsAt2 );
+
+       iMeeting1->setEndsAt( iEndsAt1 );
+       QCOMPARE( iMeeting1->endsAt(), iEndsAt1 );
+}
+
+void TestMeeting::testSetSubject()
+{
+       iMeeting1->setSubject( iSubject2 );
+       QCOMPARE( iMeeting1->subject(), iSubject2 );
+
+       iMeeting1->setSubject( iSubject1 );
+       QCOMPARE( iMeeting1->subject(), iSubject1 );
+}
+
+void TestMeeting::testSetDescription()
+{
+       iMeeting1->setDescription( iDescription1 );
+       QCOMPARE( iMeeting1->description(), iDescription1 );
+
+       iMeeting2->setDescription( iDescription2 );
+       QCOMPARE( iMeeting2->description(), iDescription2 );
+}
+
+void TestMeeting::testEquals()
+{
+       iMeeting2->setEndsAt( iEndsAt2 );
+       QCOMPARE( iMeeting1->equals( iMeeting2 ), false );
+
+       iMeeting2->setEndsAt( iEndsAt1 );
+       QCOMPARE( iMeeting1->equals( iMeeting2 ), true );
+}
+
+void TestMeeting::testToString()
+{
+       QString meeting1ToString = QString( "[MEETING: id1:%1 id2:%2 in:%3 from:%4 until:%5 by:%6 subject:%7 description:%8]" )
+                                          .arg( iPrimaryId1 )
+                                          .arg( iSecondaryId1 )
+                                          .arg( iRoom->toString() )
+                                          .arg( iStartsAt1.toString() )
+                                          .arg( iEndsAt1.toString() )
+                                          .arg( iMeeting1->organizer() )
+                                          .arg( iSubject1 )
+                                          .arg( iDescription1 );
+
+       QCOMPARE( iMeeting1->toString(), meeting1ToString );
+}
diff --git a/tests/Domain/Meeting/TestMeeting.h b/tests/Domain/Meeting/TestMeeting.h
new file mode 100644 (file)
index 0000000..31c06a2
--- /dev/null
@@ -0,0 +1,45 @@
+#include <QObject>
+#include <QDateTime>
+
+class Meeting;
+class Room;
+
+class TestMeeting: public QObject
+{
+       Q_OBJECT
+
+private slots:
+       void initTestCase();
+       void init();
+       void cleanup();
+       void testPrimaryId();
+       void testSecondaryId();
+       void testGetAndSetOrganizer();
+       void testStartsAt();
+       void testEndsAt();
+       void testSubject();
+       void testDescription();
+       void testDetailsAvailable();
+       void testSetSecondaryId();
+       void testSetStartsAt();
+       void testSetEndsAt();
+       void testSetSubject();
+       void testSetDescription();
+       void testEquals();
+       void testToString();
+       void cleanupTestCase();
+
+private:
+       Meeting *iMeeting1, *iMeeting2;
+
+       int iPrimaryId1, iPrimaryId2;
+       int iSecondaryId1, iSecondaryId2;
+       Room *iRoom;
+       QString iOrganizer1Name, iOrganizer1EMail;
+       QString iOrganizer2Name, iOrganizer2EMail;
+       QDateTime iStartsAt1, iStartsAt2;
+       QDateTime iEndsAt1, iEndsAt2;
+       QString iSubject1, iSubject2;
+       QString iDescription1, iDescription2;
+
+};
diff --git a/tests/Domain/Meeting/TestMeetingOnly.cpp b/tests/Domain/Meeting/TestMeetingOnly.cpp
new file mode 100644 (file)
index 0000000..5830ec8
--- /dev/null
@@ -0,0 +1,11 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestMeeting.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       TestMeeting testMeeting;
+       QTest::qExec( &testMeeting );
+}
diff --git a/tests/Domain/Meeting/TestMeetingOnly.pro b/tests/Domain/Meeting/TestMeetingOnly.pro
new file mode 100644 (file)
index 0000000..c0cc0bc
--- /dev/null
@@ -0,0 +1,11 @@
+QT += testlib
+TEMPLATE = app
+CONFIG += qtestlib
+INCLUDEPATH += ../../../src/Domain/
+HEADERS += ../../../src/Domain/Meeting.h \
+    ../../../src/Domain/Room.h \
+    TestMeeting.h
+SOURCES += ../../../src/Domain/Meeting.cpp \
+    ../../../src/Domain/Room.cpp \
+    TestMeeting.cpp \
+    TestMeetingOnly.cpp
diff --git a/tests/Domain/Room/TestRoom.cpp b/tests/Domain/Room/TestRoom.cpp
new file mode 100644 (file)
index 0000000..6895896
--- /dev/null
@@ -0,0 +1,71 @@
+#include <QtTest/QtTest>
+
+#include "Room.h"
+#include "TestRoom.h"
+
+void TestRoom::initTestCase()
+{
+       iName1 = "myName";
+       iName2 = "otherName";
+       iAddress1 = "myAddress";
+       iAddress2 = "otherAddress";
+
+       iRoom1 = new Room( iName1, iAddress1 );
+       iRoom2 = new Room( iName1, iAddress2 );
+       iRoom3 = new Room( iName2, iAddress1 );
+       iRoom4 = new Room( iName2, iAddress2 );
+
+       QVERIFY( iRoom1 != 0 );
+       QVERIFY( iRoom2 != 0 );
+       QVERIFY( iRoom2 != 0 );
+       QVERIFY( iRoom4 != 0 );
+}
+
+void TestRoom::cleanupTestCase()
+{
+       delete iRoom1;
+       iRoom1 = 0;
+       delete iRoom2;
+       iRoom2 = 0;
+       delete iRoom2;
+       iRoom2 = 0;
+       delete iRoom4;
+       iRoom4 = 0;
+}
+
+void TestRoom::init()
+{
+       //qDebug("Debug line");
+}
+
+void TestRoom::cleanup()
+{
+       //nothing to do
+}
+
+void TestRoom::testName()
+{
+       QCOMPARE( iRoom1->name(), iName1 );
+}
+
+void TestRoom::testAddress()
+{
+       QCOMPARE( iRoom1->address(), iAddress1 );
+}
+
+void TestRoom::testEquals()
+{
+       QCOMPARE( iRoom1->equals( iRoom1 ), true );
+       QCOMPARE( iRoom1->equals( iRoom2 ), false );
+       QCOMPARE( iRoom1->equals( iRoom3 ), false );
+       QCOMPARE( iRoom1->equals( iRoom4 ), false );
+}
+
+void TestRoom::testToString()
+{
+       QString room1ToString = QString( "[Room: name:%1 address:%2 ]" )
+                                       .arg( iName1 )
+                                       .arg( iAddress1 );
+
+       QCOMPARE( iRoom1->toString(), room1ToString );
+}
diff --git a/tests/Domain/Room/TestRoom.h b/tests/Domain/Room/TestRoom.h
new file mode 100644 (file)
index 0000000..5e5b373
--- /dev/null
@@ -0,0 +1,50 @@
+#include <QtTest/QtTest>
+
+#include "Room.h"
+
+class TestRoom: public QObject
+{
+       Q_OBJECT
+
+private slots:
+       /*!
+        * \function initTestCase is executed before testcase
+        */
+       void initTestCase();
+       /*!
+        * \function init is executed before individual test
+        */
+       void init();
+       /*!
+        *
+        * \function cleanup is executed after individual test
+        */
+       void cleanup();
+       /*!
+        * test for name
+        */
+       void testName();
+       /*!
+        * test for address
+        */
+       void testAddress();
+       /*!
+        * test for equals
+        */
+       void testEquals();
+       /*!
+        * test for toString
+        */
+       void testToString();
+       /*!
+        * \function cleanupTestCase is executed after testcase
+        */
+       void cleanupTestCase();
+
+private:
+       Room *iRoom1, *iRoom2, *iRoom3, *iRoom4;
+
+       QString iName1, iName2;
+       QString iAddress1, iAddress2;
+
+};
diff --git a/tests/Domain/Room/TestRoomOnly.cpp b/tests/Domain/Room/TestRoomOnly.cpp
new file mode 100644 (file)
index 0000000..f8f97dd
--- /dev/null
@@ -0,0 +1,11 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestRoom.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       TestRoom testRoom;
+       QTest::qExec( &testRoom );
+}
diff --git a/tests/Domain/Room/TestRoomOnly.pro b/tests/Domain/Room/TestRoomOnly.pro
new file mode 100644 (file)
index 0000000..935522a
--- /dev/null
@@ -0,0 +1,10 @@
+ QT += testlib
+ TEMPLATE = app
+ CONFIG += qtestlib
+ INCLUDEPATH += ../../../src/Domain/
+ HEADERS += ../../../src/Domain/Room.h \
+     TestRoom.h
+ SOURCES += ../../../src/Domain/Room.cpp \
+     TestRoom.cpp \
+     TestRoomOnly.cpp
+
diff --git a/tests/IO/Communication/TestCommunication.cpp b/tests/IO/Communication/TestCommunication.cpp
new file mode 100644 (file)
index 0000000..df94925
--- /dev/null
@@ -0,0 +1,100 @@
+#include <QtTest/QtTest>
+#include "Configuration.h"
+#include "ConnectionSettings.h"
+#include "TestCommunication.h"
+#include "Communication.h"
+#include "MessagingUtils.h"
+#include <QString>
+#include <QSignalSpy>
+
+static const QString server = "192.168.0.35";
+static const QString user   = "maemo";
+static const QString pass   = "P@ssw0rd";
+static const unsigned int refresh = 1;
+
+void TestCommunication::initTestCase()
+{
+    ConnectionSettings *conn = new ConnectionSettings( server, user, pass, refresh );
+    QVERIFY( conn != 0 );
+       iComm = new Communication( *conn );
+       QVERIFY( iComm != 0 );
+    delete conn;
+    conn = NULL;
+       connect( iComm,
+                        SIGNAL( requestFinished( int, QHttp::Error ) ),
+                        this,
+                        SLOT( requestFinished( int, QHttp::Error ) )
+                       );
+}
+
+void TestCommunication::cleanupTestCase()
+{
+       delete iComm;
+}
+
+void TestCommunication::init() { }
+
+void TestCommunication::cleanup() { }
+
+void TestCommunication::testPublicSignals()
+{
+       QSignalSpy rp( iComm, SIGNAL(readProgress( int, int, int )) );
+       QCOMPARE( rp.isValid(), true );
+       QSignalSpy rs( iComm, SIGNAL(requestStarted( int )) );
+       QCOMPARE( rs.isValid(), true );
+       qRegisterMetaType<QHttp::Error>("QHttp::Error");
+       QSignalSpy rf( iComm, SIGNAL(requestFinished( int, QHttp::Error )) );
+       QCOMPARE( rf.isValid(), true );
+       
+       iRequestId = iComm->request( "", QString("").toAscii() );
+       for(int i=0; iRequestId != 0 && i < 5000/250; i++ )
+               QTest::qWait( 250 );
+       
+       //verify requestStarted
+       QCOMPARE( rs.count(),  1 );
+       QList<QVariant> args = rs.takeFirst();
+       QCOMPARE( args.at(0).type(), QVariant::Int );
+       
+       //verify requestFinished
+       QCOMPARE( rf.count(), 1 );
+       args = rf.takeFirst();
+       QCOMPARE( args.at(0).type(), QVariant::Int );
+       QCOMPARE( args.at(1).typeName(), "QHttp::Error" );
+       
+       //verify readProgress
+       QCOMPARE( rp.count(), 1 );
+       args = rp.takeFirst();
+       QCOMPARE( args.at(0).type(), QVariant::Int );
+       QCOMPARE( args.at(1).type(), QVariant::Int );
+       QCOMPARE( args.at(2).type(), QVariant::Int );
+}
+
+void TestCommunication::testRequestAndResponse()
+{
+       const QString command = "text/xml; charset=utf-8; action=\"http://schemas.microsoft.com/exchange/services/2006/messages/GetUserAvailability\"";
+    QFile file("input.xml");
+    if(!file.open(QIODevice::ReadOnly))
+    {
+       QFAIL( "Error opening input.xml" );
+    }
+    QByteArray content = file.readAll();
+
+       iRequestId = iComm->request( command, content );
+       int id_fail = iComm->request( "", QString("").toAscii() );
+       QVERIFY( iRequestId != 0 );
+       QCOMPARE( id_fail, 0 );
+       for(int i=0; iRequestId != 0 && i < 5000/250; i++ )
+               QTest::qWait( 250 );
+       const QByteArray& response = iComm->response( 0 );
+       QVERIFY( response.contains("GetUserAvailabilityResponse") );
+       iRequestId = iComm->request( "", QString("").toAscii() );
+       QVERIFY( iRequestId != 0 );
+       QVERIFY( response.isEmpty() );
+}
+
+void TestCommunication::requestFinished( int aRequestId, QHttp::Error /*aError*/ )
+{
+       QCOMPARE( aRequestId, iRequestId );
+       iRequestId = 0;
+}
+
diff --git a/tests/IO/Communication/TestCommunication.h b/tests/IO/Communication/TestCommunication.h
new file mode 100644 (file)
index 0000000..1fd9e4d
--- /dev/null
@@ -0,0 +1,21 @@
+#include <QtTest/QtTest>
+#include "Communication.h"
+#include "ConnectionSettings.h"
+
+class TestCommunication: public QObject
+{
+       Q_OBJECT
+
+private slots:
+       void initTestCase();
+       void init();
+       void cleanup();
+       void cleanupTestCase();
+       void testPublicSignals();
+    void testRequestAndResponse();
+       void requestFinished( int aRequestId, QHttp::Error aError );
+
+private:
+       Communication* iComm;
+       int iRequestId;
+};
diff --git a/tests/IO/Communication/TestCommunicationOnly.cpp b/tests/IO/Communication/TestCommunicationOnly.cpp
new file mode 100644 (file)
index 0000000..c2be501
--- /dev/null
@@ -0,0 +1,11 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestCommunication.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       TestCommunication test;
+       QTest::qExec( &test );
+}
diff --git a/tests/IO/Communication/TestCommunicationOnly.pro b/tests/IO/Communication/TestCommunicationOnly.pro
new file mode 100644 (file)
index 0000000..7def6c5
--- /dev/null
@@ -0,0 +1,13 @@
+QT += testlib xml network
+TEMPLATE = app
+CONFIG += qtestlib debug
+INCLUDEPATH += ../../../src/Domain/ \
+    ../../../src/Domain/Configuration/ \
+    ../../../src/IO/Communication/
+HEADERS += ../../../src/Domain/Configuration/ConnectionSettings.h \
+    TestCommunication.h \
+    ../../../src/IO/Communication/Communication.h
+SOURCES += ../../../src/Domain/Configuration/ConnectionSettings.cpp \
+    ../../../src/IO/Communication/Communication.cpp \
+    TestCommunication.cpp \
+    TestCommunicationOnly.cpp
diff --git a/tests/IO/Communication/input.xml b/tests/IO/Communication/input.xml
new file mode 100644 (file)
index 0000000..3fb8cfd
--- /dev/null
@@ -0,0 +1,40 @@
+<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
+    <soap:Body>
+        <GetUserAvailabilityRequest xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
+            <t:TimeZone xmlns="http://schemas.microsoft.com/exchange/services/2006/types">
+                <Bias>120</Bias>
+                       <StandardTime>
+                           <Bias>0</Bias>
+                           <Time>09:18:00</Time>
+                           <DayOrder>23</DayOrder>
+                           <Month>4</Month>
+                           <DayOfWeek>Thursday</DayOfWeek>
+                       </StandardTime>
+                <DaylightTime>
+                           <Bias>-60</Bias>
+                           <Time>09:18:00</Time>
+                           <DayOrder>23</DayOrder>
+                           <Month>4</Month>
+                           <DayOfWeek>Thursday</DayOfWeek>
+                       </DaylightTime>
+            </t:TimeZone>
+            <MailboxDataArray>
+                <t:MailboxData>
+                           <t:Email>
+                               <t:Address>meetingroomtest@test.local</t:Address>
+                    </t:Email>
+                           <t:AttendeeType>Room</t:AttendeeType>
+                           <t:ExcludeConflicts>false</t:ExcludeConflicts>
+                       </t:MailboxData>
+            </MailboxDataArray>
+            <t:FreeBusyViewOptions>
+                   <t:TimeWindow>
+                           <t:StartTime>2009-04-20T00:00:00</t:StartTime>
+                           <t:EndTime>2009-04-24T23:59:59</t:EndTime>
+                       </t:TimeWindow>
+                       <t:MergedFreeBusyIntervalInMinutes>60</t:MergedFreeBusyIntervalInMinutes>
+                       <t:RequestedView>DetailedMerged</t:RequestedView>
+            </t:FreeBusyViewOptions>
+        </GetUserAvailabilityRequest>
+    </soap:Body>
+</soap:Envelope>
diff --git a/tests/IO/CommunicationManager/TestCommunicationManager.cpp b/tests/IO/CommunicationManager/TestCommunicationManager.cpp
new file mode 100644 (file)
index 0000000..a339d43
--- /dev/null
@@ -0,0 +1,151 @@
+#include <QtTest/QtTest>
+#include "Configuration.h"
+#include "ConnectionSettings.h"
+#include "TestCommunicationManager.h"
+#include "Communication.h"
+#include "Room.h"
+#include "Meeting.h"
+#include <QString>
+#include <QSignalSpy>
+#include <QDateTime>
+
+static const QString server = "192.168.0.35";
+static const QString user   = "maemo";
+static const QString pass   = "P@ssw0rd";
+static const unsigned int refresh = 1;
+
+void TestCommunicationManager::initTestCase()
+{
+    ConnectionSettings *conn = new ConnectionSettings( server, user, pass, refresh );
+    QVERIFY( conn != 0 );
+       iMgr = new CommunicationManager( *conn );
+       QVERIFY( iMgr != 0 );
+    delete conn;
+    conn = NULL;
+}
+
+void TestCommunicationManager::cleanupTestCase()
+{
+       delete iMgr;
+}
+
+void TestCommunicationManager::init() { }
+
+void TestCommunicationManager::cleanup() { }
+
+void TestCommunicationManager::testErrorSignal()
+{
+       ConnectionSettings *conn = new ConnectionSettings( QString(""), user, pass, refresh );
+       CommunicationManager *mgr = new CommunicationManager( *conn );
+       delete conn;
+
+       QDateTime start = QDateTime::currentDateTime();
+       QDateTime end = start.addDays(14);
+       Room room( "Room name","Room address" );
+
+       connect( mgr,
+                        SIGNAL( error( int, CommunicationManager::CommunicationType  ) ),
+                        this,
+                        SLOT( handleError(int, CommunicationManager::CommunicationType  ) )
+                       );
+       
+       iError = 0;
+       mgr->fetchMeetings( start, end, room );
+       for(int i=0; iError == 0 && i < 5000/250; i++ )
+               QTest::qWait( 250 );
+       
+       if( iError == 0 )
+       {
+               QFAIL( "error signal not emitted" );
+       }
+       
+       delete mgr;
+}
+
+void TestCommunicationManager::testFetchMeetings()
+{
+       qRegisterMetaType<CommunicationManager::CommunicationType>("CommunicationManager::CommunicationType");
+       QSignalSpy rp( iMgr, SIGNAL(readProgress( int, int, CommunicationManager::CommunicationType )) );
+       QCOMPARE( rp.isValid(), true );
+
+       connect( iMgr,
+                        SIGNAL( meetingsFetched( const QList<Meeting*>& ) ),
+                        this,
+                        SLOT( meetingsFetched( const QList<Meeting*>& ) )
+                       );
+       connect( iMgr,
+                        SIGNAL( error( int, CommunicationManager::CommunicationType  ) ),
+                        this,
+                        SLOT( handleError(int, CommunicationManager::CommunicationType  ) )
+                       );
+       QDateTime start = QDateTime::fromString( QString("04.05.2009"), QString("dd.MM.yyyy") );
+       QDateTime end = QDateTime::fromString( QString("09.05.2009"), QString("dd.MM.yyyy") );
+       Room room( "TestRoom", "meetingroomtest@test.local" );
+       iMgr->fetchMeetings( start, end, room );
+       iError = 0;
+       for(int i=0; iError == 0 && i < 5000/250; i++ )
+               QTest::qWait( 250 );
+
+       if( iError == 0 )
+       {
+               QFAIL("signal meetingsFetched not emitted");
+       }
+
+       QVERIFY( iMeetings.count() > 0 );
+       for( int i=0; i < iMeetings.count(); i++)
+       {
+               Meeting *m = iMeetings[i];
+               qDebug() << m->toString();
+       }
+
+       //verify readProgress
+       QCOMPARE( rp.count(), 1 );
+       QList<QVariant> args = rp.takeFirst();
+       QCOMPARE( args.at(0).type(), QVariant::Int );
+       QCOMPARE( args.at(1).type(), QVariant::Int );
+       QCOMPARE( args.at(2).typeName(), "CommunicationManager::CommunicationType" );
+}
+
+void TestCommunicationManager::testFetchMeetingDetails()
+{
+       connect( iMgr,
+                        SIGNAL( meetingDetailsFetched( Meeting& ) ),
+                        this,
+                        SLOT( meetingDetailsFetched( Meeting& ) )
+                       );
+       Meeting* m = iMeetings[0];
+       QVERIFY( m->secondaryId().isEmpty() );
+//     QVERIFY( !m->primaryId().isEmpty() );
+       iMgr->fetchMeetingDetails( *m );
+       iError = 0;
+       for(int i=0; iError == 0 && i < 5000/250; i++ )
+               QTest::qWait( 250 );
+
+       if( iError == 0 )
+       {
+               QFAIL("signal meetingDetailsFetched not emitted");
+       }
+       QVERIFY( !m->secondaryId().isEmpty() );
+       QVERIFY( m->detailsAvailable() );
+       qDebug() << m->toString();
+}
+
+void TestCommunicationManager::handleError( int aCode, CommunicationManager::CommunicationType aType )
+{
+       QWARN("TestCommunicationManager::handleError");
+       QCOMPARE( aType, CommunicationManager::FetchingCommunication );
+       QVERIFY( aCode != 0 );
+       iError = aCode;
+}
+
+void TestCommunicationManager::meetingsFetched( const QList<Meeting*> &aMeetings )
+{
+       iMeetings = aMeetings;
+       iError = 1;
+}
+
+void TestCommunicationManager::meetingDetailsFetched( Meeting &aDetailedMeeting )
+{
+       QCOMPARE( &aDetailedMeeting, iMeetings[0] );
+       iError = 1;
+}
diff --git a/tests/IO/CommunicationManager/TestCommunicationManager.h b/tests/IO/CommunicationManager/TestCommunicationManager.h
new file mode 100644 (file)
index 0000000..e7f607d
--- /dev/null
@@ -0,0 +1,26 @@
+#include <QtTest/QtTest>
+#include "Communication.h"
+#include "ConnectionSettings.h"
+#include "CommunicationManager.h"
+
+class TestCommunicationManager: public QObject
+{
+       Q_OBJECT
+
+private slots:
+       void initTestCase();
+       void init();
+       void cleanup();
+       void cleanupTestCase();
+       void testErrorSignal();
+       void testFetchMeetings();
+       void testFetchMeetingDetails();
+       void meetingsFetched( const QList<Meeting*> &aMeetings );
+       void meetingDetailsFetched( Meeting &aDetailedMeeting );
+       void handleError( int aCode, CommunicationManager::CommunicationType aType );
+
+private:
+       CommunicationManager* iMgr;
+       int iError;
+       QList<Meeting*> iMeetings;
+};
diff --git a/tests/IO/CommunicationManager/TestCommunicationManagerOnly.cpp b/tests/IO/CommunicationManager/TestCommunicationManagerOnly.cpp
new file mode 100644 (file)
index 0000000..e6297a1
--- /dev/null
@@ -0,0 +1,11 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestCommunicationManager.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       TestCommunicationManager test;
+       QTest::qExec( &test );
+}
diff --git a/tests/IO/CommunicationManager/TestCommunicationManagerOnly.pro b/tests/IO/CommunicationManager/TestCommunicationManagerOnly.pro
new file mode 100644 (file)
index 0000000..2612b2e
--- /dev/null
@@ -0,0 +1,21 @@
+QT += testlib xml network
+TEMPLATE = app
+CONFIG += qtestlib debug
+INCLUDEPATH += ../../../src/Domain/ \
+    ../../../src/Domain/Configuration/ \
+    ../../../src/IO/Communication/
+HEADERS += ../../../src/Domain/Configuration/ConnectionSettings.h \
+    TestCommunicationManager.h \
+    ../../../src/IO/Communication/Communication.h \
+    ../../../src/IO/Communication/CommunicationManager.h \
+    ../../../src/Domain/Meeting.h \
+    ../../../src/Domain/Room.h \
+    ../../../src/IO/Communication/MessagingUtils.h
+SOURCES += ../../../src/Domain/Configuration/ConnectionSettings.cpp \
+    ../../../src/IO/Communication/Communication.cpp \
+    ../../../src/IO/Communication/CommunicationManager.cpp \
+    ../../../src/Domain/Meeting.cpp \
+    ../../../src/Domain/Room.cpp \
+    ../../../src/IO/Communication/MessagingUtils.cpp \
+    TestCommunicationManager.cpp \
+    TestCommunicationManagerOnly.cpp
diff --git a/tests/QtMeetings.conf b/tests/QtMeetings.conf
new file mode 100644 (file)
index 0000000..5025781
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration password="admin" >
+
+       <connection>
+               <serverurl>jklexch01.ixonos.com</serverurl>
+               <username>username</username>
+               <password>password</password>-->
+               <!-- interval is interpreted in seconds -->
+               <refreshinterval>65</refreshinterval>
+       </connection>
+
+       <startup>
+               <powersaving enabled="false" on="08:00" off="17:00" />
+       </startup>
+
+       <display>
+               <!-- only 5 or 7 days-long weeks are supported -->
+               <schedule>
+                       <week days="5" />
+                       <day startsat="08:00" endsat="17:00" />
+               </schedule>
+               <!-- date and time format strings must be compatible with Qt's QDateTime formatting  -->
+               <dateformat>ddd dd MMM</dateformat>
+               <timeformat>hh:mm</timeformat>
+       </display>
+
+    <rooms>
+               <room>
+                       <name>Pegasus</name>
+                       <address>meetingroom.pegasus_jyv@ixonos.com</address>
+               </room>
+               <room default="true">
+                       <name>Taurus</name>
+                       <address>meetingroom.taurus_jyv@ixonos.com</address>
+               </room>
+               <room>
+                       <name>Hercules</name>
+                       <address>meetingroom.hercules@ixonos.com</address>
+               </room>
+       </rooms>
+
+       <!-- language code must be in ISO 3166-1 alpha-2 standard -->
+       <language code="EN" />
+
+</configuration>
diff --git a/tests/TestQtMeetings.cpp b/tests/TestQtMeetings.cpp
new file mode 100644 (file)
index 0000000..7cbc36c
--- /dev/null
@@ -0,0 +1,69 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+
+// Domain
+#include "TestRoom.h"
+#include "TestMeeting.h"
+#include "TestConnectionSettings.h"
+#include "TestDisplaySettings.h"
+#include "TestStartupSettings.h"
+#include "TestConfiguration.h"
+
+// Communication
+// TODO : includes here
+
+// DeviceControl
+// TODO : includes here
+
+// BusinessLogic
+#include "TestClock.h"
+#include "TestErrorMapper.h"
+#include "TestEngine.h"
+
+// UserInterface
+#include "TestMeetingRoomCombo.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       /************ Domain ************/
+       TestRoom testRoom;
+       QTest::qExec( &testRoom );
+
+       TestMeeting testMeeting;
+       QTest::qExec( &testMeeting );
+
+       TestConnectionSettings testConnectionSettings;
+       QTest::qExec( &testConnectionSettings );
+
+       TestDisplaySettings testDisplaySettings;
+       QTest::qExec( &testDisplaySettings );
+
+       TestStartupSettings testStartupSettings;
+       QTest::qExec( &testStartupSettings );
+
+       TestConfiguration testConfiguration;
+       QTest::qExec( &testConfiguration );
+
+       /************ Communication ************/
+       // TODO : tests here
+
+       /************ DeviceControl ************/
+       // TODO : tests here
+
+       /************ BusinessLogic ************/
+       TestClock testClock;
+       QTest::qExec( &testClock );
+
+       TestErrorMapper testErrorMapper;
+       QTest::qExec( &testErrorMapper );
+
+       TestEngine testEngine;
+       // TODO : TestEngine ends up in Segmentation fault for some reason if run together with other tests. Individually everything goes OK.
+//     QTest::qExec( &testEngine );
+
+       /************ UserInterface ************/
+       TestMeetingRoomCombo testMeetingRoomCombo;
+       QTest::qExec( &testMeetingRoomCombo );
+}
diff --git a/tests/TestQtMeetings.pro b/tests/TestQtMeetings.pro
new file mode 100644 (file)
index 0000000..4f6f51b
--- /dev/null
@@ -0,0 +1,107 @@
+QT += testlib \
+    xml \
+    network
+TEMPLATE = app
+CONFIG += qtestlib
+CONFIG += link_pkgconfig
+PKGCONFIG += libalarm
+
+INCLUDEPATH += ../src/Domain/ \
+    ../src/Domain/Configuration/ \
+    ../src/IO/ \
+    ../src/IO/Communication/ \
+    ../src/IO/DeviceControl/ \
+    ../src/BusinessLogic/ \
+    ../src/BusinessLogic/Utils/ \
+    ../src/UserInterface/ \
+    ../src/UserInterface/Components/ \
+    ../src/UserInterface/Utils/ \
+    ../src/UserInterface/Views/ \
+    Domain/Room/ \
+    Domain/Meeting/ \
+    Domain/Configuration/ConnectionSettings/ \
+    Domain/Configuration/DisplaySettings/ \
+    Domain/Configuration/StartupSettings/ \
+    Domain/Configuration/Configuration/ \
+    BusinessLogic/Utils/Clock/ \
+    BusinessLogic/Utils/ErrorMapper/ \
+    BusinessLogic/Engine/ \
+    UserInterface/Components/MeetingRoomCombo/
+
+HEADERS += ../src/Domain/Room.h \
+    ../src/Domain/Meeting.h \
+    ../src/Domain/Configuration/ConnectionSettings.h \
+    ../src/Domain/Configuration/StartupSettings.h \
+    ../src/Domain/Configuration/DisplaySettings.h \
+    ../src/Domain/Configuration/Configuration.h \
+    ../src/IO/Communication/Communication.h \
+    ../src/IO/Communication/CommunicationManager.h \
+    ../src/IO/DeviceControl/AlarmSender.h \
+    ../src/IO/DeviceControl/HWKeyListener.h \
+    ../src/IO/DeviceControl/DeviceDataStorage.h \
+    ../src/IO/DeviceControl/DeviceManager.h \
+    ../src/BusinessLogic/Utils/ErrorMapper.h \
+    ../src/BusinessLogic/Utils/Clock.h \
+    ../src/BusinessLogic/Engine.h \
+    ../src/UserInterface/Utils/ToolBox.h \
+    ../src/UserInterface/Utils/PopUpMessageBox.h \
+    ../src/UserInterface/Components/ObservedWidget.h \
+    ../src/UserInterface/Components/TimeDisplayWidget.h \
+    ../src/UserInterface/Components/DigitalTimeDisplayWidget.h \
+    ../src/UserInterface/Components/MeetingRoomCombo.h \
+    ../src/UserInterface/Components/ScheduleWidget.h \
+    ../src/UserInterface/Views/RoomStatusIndicatorWidget.h \
+    ../src/UserInterface/Views/WeeklyViewWidget.h \
+    ../src/UserInterface/Views/MeetingInfoDialog.h \
+    ../src/UserInterface/WindowManager.h \
+    Domain/Room/TestRoom.h \
+    Domain/Meeting/TestMeeting.h \
+    Domain/Configuration/ConnectionSettings/TestConnectionSettings.h \
+    Domain/Configuration/DisplaySettings/TestDisplaySettings.h \
+    Domain/Configuration/StartupSettings/TestStartupSettings.h \
+    Domain/Configuration/Configuration/TestConfiguration.h \
+    BusinessLogic/Utils/Clock/TestClock.h \
+    BusinessLogic/Utils/ErrorMapper/TestErrorMapper.h \
+    BusinessLogic/Engine/TestEngine.h \
+    UserInterface/Components/MeetingRoomCombo/TestMeetingRoomCombo.h
+
+SOURCES += ../src/Domain/Room.cpp \
+    ../src/Domain/Meeting.cpp \
+    ../src/Domain/Configuration/ConnectionSettings.cpp \
+    ../src/Domain/Configuration/StartupSettings.cpp \
+    ../src/Domain/Configuration/DisplaySettings.cpp \
+    ../src/Domain/Configuration/Configuration.cpp \
+    ../src/IO/Communication/Communication.cpp \
+    ../src/IO/Communication/CommunicationManager.cpp \
+    ../src/IO/DeviceControl/AlarmSender.cpp \
+    ../src/IO/DeviceControl/HWKeyListener.cpp \
+    ../src/IO/DeviceControl/DeviceDataStorage.cpp \
+    ../src/IO/DeviceControl/DeviceManager.cpp \
+    ../src/BusinessLogic/Utils/ErrorMapper.cpp \
+    ../src/BusinessLogic/Utils/Clock.cpp \
+    ../src/BusinessLogic/Engine.cpp \
+    ../src/UserInterface/Utils/ToolBox.cpp \
+    ../src/UserInterface/Utils/PopUpMessageBox.cpp \
+    ../src/UserInterface/Components/ObservedWidget.cpp \
+    ../src/UserInterface/Components/TimeDisplayWidget.cpp \
+    ../src/UserInterface/Components/DigitalTimeDisplayWidget.cpp \
+    ../src/UserInterface/Components/MeetingRoomCombo.cpp \
+    ../src/UserInterface/Components/ScheduleWidget.cpp \
+    ../src/UserInterface/Views/RoomStatusIndicatorWidget.cpp \
+    ../src/UserInterface/Views/WeeklyViewWidget.cpp \
+    ../src/UserInterface/Views/MeetingInfoDialog.cpp \
+    ../src/UserInterface/WindowManager.cpp \
+    Domain/Room/TestRoom.cpp \
+    Domain/Meeting/TestMeeting.cpp \
+    Domain/Configuration/ConnectionSettings/TestConnectionSettings.cpp \
+    Domain/Configuration/DisplaySettings/TestDisplaySettings.cpp \
+    Domain/Configuration/StartupSettings/TestStartupSettings.cpp \
+    Domain/Configuration/Configuration/TestConfiguration.cpp \
+    BusinessLogic/Utils/Clock/TestClock.cpp \
+    BusinessLogic/Utils/ErrorMapper/TestErrorMapper.cpp \
+    BusinessLogic/Engine/TestEngine.cpp \
+    UserInterface/Components/MeetingRoomCombo/TestMeetingRoomCombo.cpp \
+    TestQtMeetings.cpp
+
+RESOURCES += ../resources/BusinessLogic.qrc \
+    ../resources/UserInterface.qrc
diff --git a/tests/UserInterface/Components/MeetingRoomCombo/TestMeetingRoomCombo.cpp b/tests/UserInterface/Components/MeetingRoomCombo/TestMeetingRoomCombo.cpp
new file mode 100644 (file)
index 0000000..3a37d6f
--- /dev/null
@@ -0,0 +1,101 @@
+#include <QtTest/QtTest>
+#include "MeetingRoomCombo.h"
+#include "Room.h"
+#include "TestMeetingRoomCombo.h"
+#include <QApplication>
+
+void TestMeetingRoomCombo::initTestCase()
+{
+       iRooms.append( new Room( "Hercules", "meetingroom.hercules@ixonos.com" ) );
+       iRooms.append( new Room( "Pegasus", "meetingroom.pegasus_jyv@ixonos.com" ) );
+       iRooms.append( new Room( "Taurus", "meetingroom.taurus_jyv@ixonos.com" ) );
+
+       iCombo = new MeetingRoomCombo( iRooms );
+       QVERIFY( iCombo != 0 );
+}
+
+void TestMeetingRoomCombo::cleanupTestCase()
+{
+       delete iCombo;
+       iCombo = NULL;
+}
+
+void TestMeetingRoomCombo::init()
+{
+}
+
+void TestMeetingRoomCombo::cleanup()
+{
+}
+
+void TestMeetingRoomCombo::testCount()
+{
+       QCOMPARE( iCombo->count(), iRooms.count() );
+}
+
+void TestMeetingRoomCombo::testCurrentIndex()
+{
+       iCombo->setCurrentIndex( 0 );
+       QCOMPARE( iCombo->currentIndex(), 0 );
+
+       iCombo->setCurrentIndex( -10 );
+       QCOMPARE( iCombo->currentIndex(), -1 );
+
+       iCombo->setCurrentIndex( 10 );
+       QCOMPARE( iCombo->currentIndex(), -1 );
+
+       iCombo->setCurrentRoom( iRooms.at( 1 ) );
+       QCOMPARE( iCombo->currentIndex(), 1 );
+}
+
+void TestMeetingRoomCombo::testCurrentRoom()
+{
+       iCombo->setCurrentRoom( iRooms.at( 1 ) );
+       QCOMPARE( iCombo->currentRoom()->equals( iRooms.at( 1 ) ), true );
+       QCOMPARE( iCombo->currentRoom()->equals( iRooms.at( 0 ) ), false );
+}
+
+void TestMeetingRoomCombo::testSetCurrentIndex()
+{
+       for ( int i = 0; i < iRooms.count(); i++ )
+       {
+               iCombo->setCurrentIndex( i );
+               QCOMPARE( iCombo->currentIndex(), i );
+       }
+}
+
+void TestMeetingRoomCombo::testSetCurrentRoom()
+{
+       for ( int i = 0; i < iRooms.count(); i++ )
+       {
+               iCombo->setCurrentRoom( iRooms[i] );
+               QCOMPARE( iCombo->currentRoom(), iRooms[i] );
+       }
+}
+
+void TestMeetingRoomCombo::testSetCurrentRoomBy()
+{
+       iCombo->setCurrentRoomBy( iRooms.at( 0 )->name() );
+       QCOMPARE( iCombo->currentIndex(), 0 );
+
+       iCombo->setCurrentRoomBy( iRooms.at( 2 )->name() );
+       QCOMPARE( iCombo->currentIndex(), 2 );
+
+       iCombo->setCurrentRoomBy( "WRONG NAME" );
+       QCOMPARE( iCombo->currentIndex(), -1 );
+}
+
+void TestMeetingRoomCombo::testFindRoom()
+{
+       for ( int i = 0; i < iRooms.count(); i++ )
+       {
+               QCOMPARE( iCombo->findRoom( iRooms[i] ), i );
+       }
+}
+
+void TestMeetingRoomCombo::testFindRoomBy()
+{
+       QCOMPARE( iCombo->findRoomBy( iRooms.at( 0 )->name() ), 0 );
+       QCOMPARE( iCombo->findRoomBy( iRooms.at( 1 )->name() ), 1 );
+       QCOMPARE( iCombo->findRoomBy( "WRONG NAME" ), -1 );
+}
diff --git a/tests/UserInterface/Components/MeetingRoomCombo/TestMeetingRoomCombo.h b/tests/UserInterface/Components/MeetingRoomCombo/TestMeetingRoomCombo.h
new file mode 100644 (file)
index 0000000..6372270
--- /dev/null
@@ -0,0 +1,27 @@
+#include <QtTest/QtTest>
+#include "MeetingRoomCombo.h"
+#include "Room.h"
+
+class TestMeetingRoomCombo: public QObject
+{
+       Q_OBJECT
+
+private slots:
+       void initTestCase();
+       void init();
+       void cleanup();
+
+       void testCount();
+       void testCurrentIndex();
+       void testCurrentRoom();
+       void testSetCurrentIndex();
+       void testSetCurrentRoom();
+       void testSetCurrentRoomBy();
+       void testFindRoom();
+       void testFindRoomBy();
+       void cleanupTestCase();
+
+private:
+       MeetingRoomCombo* iCombo;
+       QList<Room*> iRooms;
+};
diff --git a/tests/UserInterface/Components/MeetingRoomCombo/TestMeetingRoomComboOnly.cpp b/tests/UserInterface/Components/MeetingRoomCombo/TestMeetingRoomComboOnly.cpp
new file mode 100644 (file)
index 0000000..835f70c
--- /dev/null
@@ -0,0 +1,12 @@
+#include <QtTest/QtTest>
+#include <QApplication>
+
+#include "TestMeetingRoomCombo.h"
+
+int main( int argc, char *argv[] )
+{
+       QApplication app( argc, argv );
+
+       TestMeetingRoomCombo testMeetingRoomCombo;
+       QTest::qExec( &testMeetingRoomCombo );
+}
diff --git a/tests/UserInterface/Components/MeetingRoomCombo/TestMeetingRoomComboOnly.pro b/tests/UserInterface/Components/MeetingRoomCombo/TestMeetingRoomComboOnly.pro
new file mode 100644 (file)
index 0000000..bd1148d
--- /dev/null
@@ -0,0 +1,14 @@
+QT += testlib
+TEMPLATE = app
+CONFIG += qtestlib
+INCLUDEPATH += ../../../../src/UserInterface/Components/ \
+    ../../../../src/Domain/
+HEADERS += ../../../../src/UserInterface/Components/MeetingRoomCombo.h \
+    ../../../../src/UserInterface/Components/ObservedWidget.h \
+    ../../../../src/Domain/Room.h \
+    TestMeetingRoomCombo.h
+SOURCES += ../../../../src/UserInterface/Components/MeetingRoomCombo.cpp \
+    ../../../../src/UserInterface/Components/ObservedWidget.cpp \
+    ../../../../src/Domain/Room.cpp  \
+    TestMeetingRoomCombo.cpp \
+    TestMeetingRoomComboOnly.cpp
diff --git a/welcome b/welcome
deleted file mode 100644 (file)
index 6bb1d85..0000000
--- a/welcome
+++ /dev/null
@@ -1 +0,0 @@
-welcome qtmeetings