--- /dev/null
+<?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>
--- /dev/null
+[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
--- /dev/null
+# 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
--- /dev/null
+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." )
--- /dev/null
+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
--- /dev/null
+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
+
--- /dev/null
+for more information see changelog
\ No newline at end of file
--- /dev/null
+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.
--- /dev/null
+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'.
--- /dev/null
+#!/bin/sh
+
+set -e
+
+maemo-select-menu-location QtMeetings.desktop
+
+exit 0
\ No newline at end of file
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+/etc/init.d/qtmeetings-launcher
+/etc/QtMeetings.conf
--- /dev/null
+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.
--- /dev/null
+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
--- /dev/null
+#!/bin/sh
+
+set -e
+
+maemo-select-menu-location QtMeetings.desktop
+
+exit 0
\ No newline at end of file
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+<?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>
--- /dev/null
+#!/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
+
--- /dev/null
+#!/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
--- /dev/null
+#!/bin/sh
+# must be in /usr/bin/
+
+if [ -e $1 ]; then
+ mv $1 $2
+fi
--- /dev/null
+#!/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
--- /dev/null
+[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
--- /dev/null
+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
--- /dev/null
+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'.
--- /dev/null
+#!/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
--- /dev/null
+<RCC>\r
+<qresource prefix="/" >\r
+ <file alias="errortable" >xml/errortable.xml</file>\r
+</qresource>\r
+</RCC>\r
--- /dev/null
+<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>
--- /dev/null
+<?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>
--- /dev/null
+#!/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
--- /dev/null
+#!/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
+
--- /dev/null
+#!/bin/sh
+# must be in /usr/bin/
+
+if [ -e $1 ]; then
+ mv $1 $2
+fi
--- /dev/null
+#!/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
--- /dev/null
+#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();
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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() );
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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 );
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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;
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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;
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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();
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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 );
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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;
+}
+
+
+
--- /dev/null
+#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_*/
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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_*/
--- /dev/null
+#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;
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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;
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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_*/
--- /dev/null
+#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";
+ }
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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 );
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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;
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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 );
+}
+
+
+
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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 );
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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_*/
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#include "ToolBox.h"
+
+#include <QLabel>
+
+QLabel* ToolBox::createLabel( const QString &aText, const QFont &aFont )
+{
+ QLabel *label = new QLabel( aText );
+ label->setFont( aFont );
+ return label;
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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()
+{
+}
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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();
+}
--- /dev/null
+#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_*/
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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 );
+ }
+ }
+}
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+<?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>
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+};
--- /dev/null
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestEngine.h"
+
+int main( int argc, char *argv[] )
+{
+ QApplication app( argc, argv );
+
+ TestEngine testEngine;
+ QTest::qExec( &testEngine );
+}
--- /dev/null
+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
--- /dev/null
+#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();
+}
--- /dev/null
+#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;
+
+};
--- /dev/null
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestClock.h"
+
+int main( int argc, char *argv[] )
+{
+ QApplication app( argc, argv );
+
+ TestClock testClock;
+ QTest::qExec( &testClock );
+}
--- /dev/null
+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
--- /dev/null
+#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 );
+}
--- /dev/null
+#include <QObject>
+
+class TestErrorMapper: public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+ void testCodeToString();
+ void cleanupTestCase();
+
+};
--- /dev/null
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestErrorMapper.h"
+
+int main( int argc, char *argv[] )
+{
+ QApplication app( argc, argv );
+
+ TestErrorMapper testErrorMapper;
+ QTest::qExec( &testErrorMapper );
+}
--- /dev/null
+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
--- /dev/null
+<?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>
--- /dev/null
+#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 ) );
+}
--- /dev/null
+#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;
+};
--- /dev/null
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestConfiguration.h"
+
+int main( int argc, char *argv[] )
+{
+ QApplication app( argc, argv );
+
+ TestConfiguration testConfiguration;
+ QTest::qExec( &testConfiguration );
+}
--- /dev/null
+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
--- /dev/null
+#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 );
+}
--- /dev/null
+#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;
+
+};
--- /dev/null
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestConnectionSettings.h"
+
+int main( int argc, char *argv[] )
+{
+ QApplication app( argc, argv );
+
+ TestConnectionSettings testConnectionSettings;
+ QTest::qExec( &testConnectionSettings );
+}
--- /dev/null
+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
--- /dev/null
+#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 );
+}
--- /dev/null
+#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;
+
+};
--- /dev/null
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestDisplaySettings.h"
+
+int main( int argc, char *argv[] )
+{
+ QApplication app( argc, argv );
+
+ TestDisplaySettings testDisplaySettings;
+ QTest::qExec( &testDisplaySettings );
+}
--- /dev/null
+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
--- /dev/null
+#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 );
+}
--- /dev/null
+#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;
+
+};
--- /dev/null
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestStartupSettings.h"
+
+int main( int argc, char *argv[] )
+{
+ QApplication app( argc, argv );
+
+ TestStartupSettings testStartupSettings;
+ QTest::qExec( &testStartupSettings );
+}
--- /dev/null
+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
--- /dev/null
+#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 );
+}
--- /dev/null
+#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;
+
+};
--- /dev/null
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestMeeting.h"
+
+int main( int argc, char *argv[] )
+{
+ QApplication app( argc, argv );
+
+ TestMeeting testMeeting;
+ QTest::qExec( &testMeeting );
+}
--- /dev/null
+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
--- /dev/null
+#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 );
+}
--- /dev/null
+#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;
+
+};
--- /dev/null
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestRoom.h"
+
+int main( int argc, char *argv[] )
+{
+ QApplication app( argc, argv );
+
+ TestRoom testRoom;
+ QTest::qExec( &testRoom );
+}
--- /dev/null
+ 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
+
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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;
+};
--- /dev/null
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestCommunication.h"
+
+int main( int argc, char *argv[] )
+{
+ QApplication app( argc, argv );
+
+ TestCommunication test;
+ QTest::qExec( &test );
+}
--- /dev/null
+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
--- /dev/null
+<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>
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+};
--- /dev/null
+#include <QtTest/QtTest>
+#include <QApplication>
+#include "TestCommunicationManager.h"
+
+int main( int argc, char *argv[] )
+{
+ QApplication app( argc, argv );
+
+ TestCommunicationManager test;
+ QTest::qExec( &test );
+}
--- /dev/null
+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
--- /dev/null
+<?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>
--- /dev/null
+#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 );
+}
--- /dev/null
+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
--- /dev/null
+#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 );
+}
--- /dev/null
+#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;
+};
--- /dev/null
+#include <QtTest/QtTest>
+#include <QApplication>
+
+#include "TestMeetingRoomCombo.h"
+
+int main( int argc, char *argv[] )
+{
+ QApplication app( argc, argv );
+
+ TestMeetingRoomCombo testMeetingRoomCombo;
+ QTest::qExec( &testMeetingRoomCombo );
+}
--- /dev/null
+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
+++ /dev/null
-welcome qtmeetings