Initial commit (software version 0.2.0)
authorgilead <j.becher@ovi.com>
Sun, 8 Aug 2010 16:08:48 +0000 (18:08 +0200)
committerJochen Becher <jbecher@edoras.(none)>
Sun, 8 Aug 2010 16:08:48 +0000 (18:08 +0200)
162 files changed:
COPYING [new file with mode: 0644]
README [new file with mode: 0644]
data/48x48/movie-schedule.png [new file with mode: 0644]
data/clap.xcf [new file with mode: 0644]
data/movie-schedule.desktop [new file with mode: 0644]
data/scalable/movie-schedule.png [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/optify [new file with mode: 0644]
debian/postinst [new file with mode: 0755]
debian/rules [new file with mode: 0755]
movie-schedule.pro [new file with mode: 0644]
movie-schedule.pro.user (Example) [new file with mode: 0644]
src/control/actioncontroller.cpp [new file with mode: 0644]
src/control/actioncontroller.h [new file with mode: 0644]
src/control/itemmodelsortclient.cpp [new file with mode: 0644]
src/control/itemmodelsortclient.h [new file with mode: 0644]
src/control/itemmodelsortcontroller.cpp [new file with mode: 0644]
src/control/itemmodelsortcontroller.h [new file with mode: 0644]
src/control/itemmodelsortproxy.cpp [new file with mode: 0644]
src/control/itemmodelsortproxy.h [new file with mode: 0644]
src/control/locationcontroller.cpp [new file with mode: 0644]
src/control/locationcontroller.h [new file with mode: 0644]
src/control/maincontroller.cpp [new file with mode: 0644]
src/control/maincontroller.h [new file with mode: 0644]
src/control/moviecontroller.cpp [new file with mode: 0644]
src/control/moviecontroller.h [new file with mode: 0644]
src/control/settingscontroller.cpp [new file with mode: 0644]
src/control/settingscontroller.h [new file with mode: 0644]
src/control/theatercontroller.cpp [new file with mode: 0644]
src/control/theatercontroller.h [new file with mode: 0644]
src/data/cinema.cpp [new file with mode: 0644]
src/data/cinema.h [new file with mode: 0644]
src/data/cinemakey.cpp [new file with mode: 0644]
src/data/cinemakey.h [new file with mode: 0644]
src/data/cinemaschedule.cpp [new file with mode: 0644]
src/data/cinemaschedule.h [new file with mode: 0644]
src/data/location.cpp [new file with mode: 0644]
src/data/location.h [new file with mode: 0644]
src/data/movie.cpp [new file with mode: 0644]
src/data/movie.h [new file with mode: 0644]
src/data/moviekey.cpp [new file with mode: 0644]
src/data/moviekey.h [new file with mode: 0644]
src/data/scheduleentry.cpp [new file with mode: 0644]
src/data/scheduleentry.h [new file with mode: 0644]
src/data/scheduleentrykey.cpp [new file with mode: 0644]
src/data/scheduleentrykey.h [new file with mode: 0644]
src/data/settings.cpp [new file with mode: 0644]
src/data/settings.h [new file with mode: 0644]
src/main.cpp [new file with mode: 0644]
src/movieschedule.cpp [new file with mode: 0644]
src/movieschedule.h [new file with mode: 0644]
src/resources.qrc [new file with mode: 0644]
src/resources/0.png [new file with mode: 0644]
src/resources/0.svg [new file with mode: 0644]
src/resources/1.png [new file with mode: 0644]
src/resources/1.svg [new file with mode: 0644]
src/resources/10.png [new file with mode: 0644]
src/resources/10.svg [new file with mode: 0644]
src/resources/2.png [new file with mode: 0644]
src/resources/2.svg [new file with mode: 0644]
src/resources/3.png [new file with mode: 0644]
src/resources/3.svg [new file with mode: 0644]
src/resources/4.png [new file with mode: 0644]
src/resources/4.svg [new file with mode: 0644]
src/resources/5.png [new file with mode: 0644]
src/resources/5.svg [new file with mode: 0644]
src/resources/6.png [new file with mode: 0644]
src/resources/6.svg [new file with mode: 0644]
src/resources/7.png [new file with mode: 0644]
src/resources/7.svg [new file with mode: 0644]
src/resources/8.png [new file with mode: 0644]
src/resources/8.svg [new file with mode: 0644]
src/resources/9.png [new file with mode: 0644]
src/resources/9.svg [new file with mode: 0644]
src/searchclients/abstractsearchclient.cpp [new file with mode: 0644]
src/searchclients/abstractsearchclient.h [new file with mode: 0644]
src/searchclients/gpsclient.cpp [new file with mode: 0644]
src/searchclients/gpsclient.h [new file with mode: 0644]
src/searchclients/movieschedulesearchclient.cpp [new file with mode: 0644]
src/searchclients/movieschedulesearchclient.h [new file with mode: 0644]
src/searchclients/moviesearchclient.cpp [new file with mode: 0644]
src/searchclients/moviesearchclient.h [new file with mode: 0644]
src/searchclients/searchclientsemaphore.cpp [new file with mode: 0644]
src/searchclients/searchclientsemaphore.h [new file with mode: 0644]
src/searchclients/theaterschedulesearchclient.cpp [new file with mode: 0644]
src/searchclients/theaterschedulesearchclient.h [new file with mode: 0644]
src/searchclients/theatersearchclient.cpp [new file with mode: 0644]
src/searchclients/theatersearchclient.h [new file with mode: 0644]
src/src.pro [new file with mode: 0644]
src/translations/movie-schedule_de.ts [new file with mode: 0644]
src/ui/aboutdialog.cpp [new file with mode: 0644]
src/ui/aboutdialog.h [new file with mode: 0644]
src/ui/aboutdialog.ui [new file with mode: 0644]
src/ui/abstractmainwindow.cpp [new file with mode: 0644]
src/ui/abstractmainwindow.h [new file with mode: 0644]
src/ui/backgroundlabel.cpp [new file with mode: 0644]
src/ui/backgroundlabel.h [new file with mode: 0644]
src/ui/cinemapainter.cpp [new file with mode: 0644]
src/ui/cinemapainter.h [new file with mode: 0644]
src/ui/contextdialog.cpp [new file with mode: 0644]
src/ui/contextdialog.h [new file with mode: 0644]
src/ui/contextdialog.ui [new file with mode: 0644]
src/ui/daypainter.cpp [new file with mode: 0644]
src/ui/daypainter.h [new file with mode: 0644]
src/ui/locationdialog.cpp [new file with mode: 0644]
src/ui/locationdialog.h [new file with mode: 0644]
src/ui/locationdialog.ui [new file with mode: 0644]
src/ui/mainwindow.cpp [new file with mode: 0644]
src/ui/mainwindow.h [new file with mode: 0644]
src/ui/mainwindow.ui [new file with mode: 0644]
src/ui/moviedelegate.cpp [new file with mode: 0644]
src/ui/moviedelegate.h [new file with mode: 0644]
src/ui/moviemodel.cpp [new file with mode: 0644]
src/ui/moviemodel.h [new file with mode: 0644]
src/ui/moviepainter.cpp [new file with mode: 0644]
src/ui/moviepainter.h [new file with mode: 0644]
src/ui/moviescheduledelegate.cpp [new file with mode: 0644]
src/ui/moviescheduledelegate.h [new file with mode: 0644]
src/ui/movieschedulemodel.cpp [new file with mode: 0644]
src/ui/movieschedulemodel.h [new file with mode: 0644]
src/ui/moviewindow.cpp [new file with mode: 0644]
src/ui/moviewindow.h [new file with mode: 0644]
src/ui/moviewindow.ui [new file with mode: 0644]
src/ui/ratingprovider.cpp [new file with mode: 0644]
src/ui/ratingprovider.h [new file with mode: 0644]
src/ui/scheduleentryitem.cpp [new file with mode: 0644]
src/ui/scheduleentryitem.h [new file with mode: 0644]
src/ui/styleutils.cpp [new file with mode: 0644]
src/ui/styleutils.h [new file with mode: 0644]
src/ui/theaterdelegate.cpp [new file with mode: 0644]
src/ui/theaterdelegate.h [new file with mode: 0644]
src/ui/theatermodel.cpp [new file with mode: 0644]
src/ui/theatermodel.h [new file with mode: 0644]
src/ui/theaterscheduledelegate.cpp [new file with mode: 0644]
src/ui/theaterscheduledelegate.h [new file with mode: 0644]
src/ui/theaterschedulemodel.cpp [new file with mode: 0644]
src/ui/theaterschedulemodel.h [new file with mode: 0644]
src/ui/theaterwindow.cpp [new file with mode: 0644]
src/ui/theaterwindow.h [new file with mode: 0644]
src/ui/theaterwindow.ui [new file with mode: 0644]
src/ui/uiutils.cpp [new file with mode: 0644]
src/ui/uiutils.h [new file with mode: 0644]
src/utils/assertedlock.cpp [new file with mode: 0644]
src/utils/assertedlock.h [new file with mode: 0644]
src/utils/assertedlocker.cpp [new file with mode: 0644]
src/utils/assertedlocker.h [new file with mode: 0644]
src/utils/asynccall.cpp [new file with mode: 0644]
src/utils/asynccall.h [new file with mode: 0644]
src/utils/asynccallclient.cpp [new file with mode: 0644]
src/utils/asynccallclient.h [new file with mode: 0644]
src/utils/asynccallproxy.cpp [new file with mode: 0644]
src/utils/asynccallproxy.h [new file with mode: 0644]
src/utils/calendar.cpp [new file with mode: 0644]
src/utils/calendar.h [new file with mode: 0644]
src/utils/connect.h [new file with mode: 0644]
src/utils/connectivitymanager.cpp [new file with mode: 0644]
src/utils/connectivitymanager.h [new file with mode: 0644]
src/utils/timeutils.cpp [new file with mode: 0644]
src/utils/timeutils.h [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..10926e8
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,675 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..b44a61c
--- /dev/null
+++ b/README
@@ -0,0 +1,36 @@
+Welcome to the MovieSchedule source code.
+
+I am using NokiaQtSDK to develop this Qt 4.6 based application.
+Unfortunatly the released SDK is not yet ready to support all
+features I would like to have. Development to the N900 phone is not
+yet finished (it is much better on the master branch of Qt Creator).
+Even with the new Qt Mobility libraries some features are missing which
+I wanted to use to integrate MovieSchedule into the phone's software
+(like adding entries to the calendar).
+
+So I decided to develop in a quite complex environment. The file
+"movie-schedule.pro.user (Example)" is a copy of the .pro.user file that
+I use: It defines several build targets for compiling the software to the
+normal Desktop (Ubuntu in my case), the MADDE environment, MAEMO SDK and
+Qt Simulator. Only the MAEMO SDK targets for x86 and ARMEL support all
+features of the software and have a nice looking GUI. I use the Desktop
+target for debugging the main application and the other targets for my
+technical interest only. There is also a target "LUpdate" which I use to
+update the internationalization files (so far German only).
+
+To use that .pro.user file you must replace some absolut pathes like
+"/scratchbox/users/jbecher/home/jbecher/Movies/" with your own directory.
+The source code must be placed in "movie-schedule" within that directory.
+
+If you wonder why I decided to have "movie-schedule" in the scratchbox: I
+need this to build the software within the MAEMO SDK.
+
+To deploy a debian package of the software goto the movie-schedule directory
+and enter "dpkg-buildpackage -rfakeroot".
+
+If you plan to improve the software or to cross compile it for another
+phone (e.g. Symbian) please contact me (Jochen Becher <j.becher@ovi.com>). 
+I would like to coordinate those efforts.
+
+Regards, Jochen "gilead" Becher
+
diff --git a/data/48x48/movie-schedule.png b/data/48x48/movie-schedule.png
new file mode 100644 (file)
index 0000000..c592a83
Binary files /dev/null and b/data/48x48/movie-schedule.png differ
diff --git a/data/clap.xcf b/data/clap.xcf
new file mode 100644 (file)
index 0000000..efb0dc6
Binary files /dev/null and b/data/clap.xcf differ
diff --git a/data/movie-schedule.desktop b/data/movie-schedule.desktop
new file mode 100644 (file)
index 0000000..594288b
--- /dev/null
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Encoding=UTF-8
+Version=0.1.0
+Type=Application
+Name=MovieSchedule
+Exec=/usr/bin/movie-schedule
+Icon=movie-schedule
+X-Window-Icon=movie-schedule
+X-HildonDesk-ShowInToolbar=true
+X-Osso-Type=application/x-executable
+Terminal=false
+Name[de_DE]=movie-schedule.desktop
diff --git a/data/scalable/movie-schedule.png b/data/scalable/movie-schedule.png
new file mode 100644 (file)
index 0000000..8462162
Binary files /dev/null and b/data/scalable/movie-schedule.png differ
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..c9e0f24
--- /dev/null
@@ -0,0 +1,13 @@
+movie-schedule (0.2.0) unstable; urgency=low
+
+  * Fixed trimming of phone numbers before calling cinema (Closes: #6110)
+  * Added work-around for trashed locations (Closes: #6109)
+
+ -- Jochen Becher <j.becher@ovi.com>  Thu, 08 Aug 2010 17:15:00 +0000
+
+movie-schedule (0.1.0) unstable; urgency=low
+
+  * Initial release (Closes: #0000)
+
+ -- Jochen Becher <j.becher@ovi.com>  Mon, 31 May 2010 23:50:29 +0000
+
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..7ed6ff8
--- /dev/null
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..0d8ed11
--- /dev/null
@@ -0,0 +1,66 @@
+Source: movie-schedule
+Section: user/network
+Priority: optional
+Maintainer: Jochen Becher <j.becher@ovi.com>
+Build-Depends: debhelper (>= 5), libqt4-core, libqt4-gui, icd2-dev, maemo-optify, liblocation-dev, libgconf2-dev, libqt4-dev, calendar-backend-dev
+Standards-Version: 3.7.3
+
+Package: movie-schedule
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Find movies at cinemas near your town.
+ MovieSchedule presents movies found in Googles movie-service.
+ Search through the movies shown in a cinema within the next
+ days or find your preferred time to watch the latest block buster.
+ Don't miss a movie by addding a calendar entry automatically or
+ google for the cinema's or movie's web page.
+XSBC-Bugtracker: https://bugs.maemo.org/enter_bug.cgi?product=movie-schedule
+XSBC-Maemo-Display-Name: MovieSchedule
+XB-Maemo-Icon-26:
+ iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAL
+ EwAACxMBAJqcGAAAAAd0SU1FB9oHGA0TFCsRMDUAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRo
+ IEdJTVBXgQ4XAAAJu0lEQVRo3u1Za0yUVxp+zjfOTZiBKQw3GZgdgQ5t0ai7ilVpKNmabrxUrElb
+ S7sxaXcb2dim+qM/TEy6TVa7TTZhE1kxKSV03VK1F1tEYKBEWqTcVAotODPM4DDKTZj79813OfsD
+ mUqVipeATXx+zbxn3u+c53vPex3gIR7iniB7EA+lUi1WvPnmW7ri4t1LCgoK9oTDXJLdbv/hVr9d
+ 9ACdO/7ll/9sVCgUz0VFRWWq1YvXP/XUUykpKSmQyRZV19XV/+9BJPDYgQMH1iYlJf29sLCQlJdX
+ qFyuyzGiyMPptGN83EPV6hii16f8abYHzBsBk8kUtWvXrqiGhqbfabXaHfHx8c9t3rxp6ZYtmwCA
+ ShKI2ZyN9vbvQQihPM+TI0f+Q3bv3ovExDQAWAGga74JJJSWlj5hMBg2aLXaDQwjW8VxQizLhhAM
+ BnD2bBNdtWo1ARjCcTxycn5PGaaSjI6OkHA4HBodHeuyWOrsExPXnGvWrBtqbf12Xixg2rp1+7bU
+ 1NRCrVabuXLlKvWyZTnRDCMDx/H48cefqMVSRwRBQCDgJxbLN8jN3QCe52G19pLY2Phvv/mm4d3k
+ 5JTzPp8vWFy8iwXAz7YZuZeTpqamRb3wwktqnU6TwjDM3uXLl2/T6xOiP/30BFg2iGAwSGNiYsg7
+ 7+xHMMhBEETYbJdQUvJPBAIBjud5v1wuD6xdm++5eLFz35dfnjxzp2e4GwukvPbaX5fHxOiWB4O+
+ jYLA57z00s44ozEdokghiqBVVVXkyhU3KKVkfHwcDQ1NMJtz4HQOIBQKWXlePDk8PNw+MjLSNTIy
+ YrVYLHf9EudKQL9///69ubm5z23YsEF37lxr1Fdffb0YoBgfH0Nz87c0OvoREggEEA6LJC9vI9ra
+ 3gXDMPB6vfjiixOldXW1nXl5T39dV1fNnj799bX7dV9vIlBUVKRetWplXE9Pv87jmXxDo9G+kZWV
+ hbff3gOGkYFlOZhMGQgE/PD7fZTneXLsWCUxm1dCFCWJEAQJYYYA5vPm5uaj4XDY2t7eDgAoK/v3
+ fXe4GQQOHz4cl52dXaXRaJ7WanW4cOECeD6Mvr4enD5dixUrVoPjOCgUWpqebiIWSw0RRWnM7/cN
+ NDXVfyEIou/kyaoL33//XdN8hecZBDiOk2u1MasffTQbarUWNTXVkCQJPM/T2tpaYjBkgWFk6Oz8
+ jlAqO+5w2It1ung6OjrG7t37N+9CZMIZBMrKjvpMJnNbTExivigySE42oLu7yy8IAudyuYYSEpZ8
+ Xln54U99fb3HpnWcTteCpvIZBHp6fgg4HJfPXbvmy09MTDojk8kvDg4OnrBarS4AQx0dHQ9c4XdT
+ Htiz560sg8FQ5HYPe8NhPiCXy0WGkZG0tCRCCEAIgdfrx+ioB4AESZKwZEkS1GrFVHkrk8Fud0EU
+ RQAAw8hgNCZPbUYIPB4/xsYmAACiKMFgSIZKJY/o2myXIUlS5Ht6egoACkII+vr6hsvLy0/5/X5+
+ VgKdnZ1rV6xY0ehwDCpbWtogly8Cw8jw5JN/QFJS4rSvoKbGAp7nIYoUS5YkYv36tZFn2O0OtLZ2
+ RHTXrVuNxMQEAADLcjhzpgE8H4YoSkhNTcG6dWsiulbrANraOiO669evQUKCHgBgsVg6X3nllXy3
+ 2+2dNYxOTnooy4Y5rVartNt/QiAQAKUAx/mxdes2MAyBUqlEKOTD+fNdkMlkaGvjYDSmIzExAaIo
+ ITY2FjZbL4LBECgFBCGIzZu3gBAGSqUSfv8Euru7IZMxaG8Pw2RKR1xcPCRJgk4Xg0uXesCyLCgF
+ RJHFpk2bIZPJwPNCWBAEeuN5mV8SCIdFcJwIQuRISEiGw+HA4KATp09XY2zsGlhWgNcbQl7e07Ba
+ rXA6nXC73Sgv/xCiyIBlBRAih16fFNGtrq7G2NgkWFaAz8de1+2H0+nE0NAQyss/AqUysKwAhlFC
+ r0+cse/4+JQuz0uEUkp+NZE1NFi4wUHnZYBE2+023aVLlzSiKBKO4/D++/+A2WyGJFEolUr4fH5Y
+ rVYwDAOr1QalUg21WgVCCAYGBtDf3w9JksBxHD744BAyMzMhSRQqlQqTk16MjdnAMAxsNhsUCgWU
+ SiUIIbDbbTfosigp+VcwIyNLcDhs/YFAMDznYs5uH/jv6OjIC9Osw+EwBEGIrCuVKshkU0aklF43
+ O404oEKhBCHTlp0q5n5uG1VgmNl0F0GhUIAQQJIkpKWl9QLkcnq68S+iyDvnFJ68Xq9WEIRzdOEh
+ UUqp1+vzPvFETu4vz8nMToGhdPqVLHCopxQgBJSQm4/L/BZGJyRy0elvk8Cv4SGBaYRCIbhcLgQC
+ gRnyYDAIl8uF8fHxGXKe53H16lW43W7ci6vdFwLNzc3Ytm0bDAYDSkpKIvKWlhZs2bIFBoMBBQUF
+ EbnD4cDrr7+OjIwMZGZmwmaz3W3p9qthVMPzfMvtYtzBgwfpde+iAGhlZSWllNKSkpIZcqPRSCml
+ tLm5mSqVyog8NjaWdnV13TaW+nw+T07OHYXR2+PgwYO4ePEibmzKn3nmGVRUVKClpQUdHR3IyMgA
+ AOTl5aGjowOFhYUoKyvD7t27AQBqtRpLly5dmCv04osvorKyElFRUQCA5ORk+P1+9PT04OOPP0ZG
+ Rgbk8qlSuaCgAAcOHEBTUxOKiorg9/unZouPPQaNRjOn/W7lKvc02EpLS4vcdQAoLCxEcXExqqqq
+ Ig7c398PpVKJtrY2FBcXw2w2Y2JiIqLz/PPP39+pxN2gsbERAFBfX4/Dhw9HLNLX1wdRFGEwGMCy
+ LDZu3AgAuHr1Kvr7+wEA27dvn/Pbv5UFmDsx12yora0FAKSnpyM/Pz8iP3XqFABgdHQUpaWlEfmJ
+ EyemB77Q6/ULmwe6u7vBsiwA4L333puxdvz4cQDAvn37IJP9/F/KsWNTM4EdO3bc0V63yhf3TGD6
+ vhuNRphMpoh8eHgYTudU5btz584bGqYwent7AQDPPvssrly5goaGhkgfPO8W+OyzzwAAy5Ytw+LF
+ iyPyioqK6wPgVOh0uoi8vr4+8vnIkSN49dVXwXFcpDeYVyfu7u6G1WoFAGRmZkKlUkXWjh49CgBI
+ SkqCQqGIyIeGhn7efNEifPLJJzMIznJ5Zq1GZ4XHc/tM7Ha7aWtr680diCTRmpoaOjk5edOaKIr0
+ 0KFD9Pz583fU1Xi9Xk929uO5d0DAM6dSYr7g8Xg9ZvPjcy8lCGFACMEDAnq9ghXm7ANnz54lGo0m
+ Ojo6esGJ8DxP9Hp9g83WP/c/+RobG31xcY/8MS4uQcEwC0mAIBQKkqyszDEAIh7iIe4v/g9Ndly/
+ gHHgugAAAABJRU5ErkJggg==
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..8eb02e4
--- /dev/null
@@ -0,0 +1,20 @@
+This package was debianized by Jochen Becher <j.becher@ovi.com> on
+Mon, 31 May 2010 23:50:29 +0000.
+
+Copyright: (C) 2010 Jochen Becher
+
+License:
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
diff --git a/debian/optify b/debian/optify
new file mode 100644 (file)
index 0000000..588192d
--- /dev/null
@@ -0,0 +1,2 @@
+auto
+
diff --git a/debian/postinst b/debian/postinst
new file mode 100755 (executable)
index 0000000..81f432b
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh -e
+
+gtk-update-icon-cache -f /usr/share/icons/hicolor
+
+exit 0
+
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..9863b42
--- /dev/null
@@ -0,0 +1,57 @@
+#!/usr/bin/make -f
+APPNAME := movie-schedule
+builddir:
+       mkdir -p builddir
+
+builddir/Makefile: builddir
+       cd builddir && qmake-qt4 PREFIX=/usr ../$(APPNAME).pro CONFIG+=maemo_sdk
+
+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/your_appname
+       cd builddir && $(MAKE) INSTALL_ROOT=$(CURDIR)/debian/$(APPNAME) 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_installdocs
+       dh_installexamples
+       dh_installman
+       dh_link
+       dh_strip
+       dh_compress
+       dh_fixperms
+       dh_installdeb
+       dh_shlibdeps
+       dh_gencontrol
+       dh_md5sums
+       maemo-optify
+       dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
+
diff --git a/movie-schedule.pro b/movie-schedule.pro
new file mode 100644 (file)
index 0000000..df2e2e7
--- /dev/null
@@ -0,0 +1,8 @@
+QMAKEVERSION = $$[QMAKE_VERSION]
+ISQT4 = $$find(QMAKEVERSION, ^[2-9])
+isEmpty( ISQT4 ) {
+        error("Use the qmake include with Qt4.4 or greater.");
+}
+
+TEMPLATE = subdirs
+SUBDIRS  = src
diff --git a/movie-schedule.pro.user (Example) b/movie-schedule.pro.user (Example)
new file mode 100644 (file)
index 0000000..73ca508
--- /dev/null
@@ -0,0 +1,421 @@
+<!DOCTYPE QtCreatorProject>
+<qtcreator>
+ <data>
+  <variable>ProjectExplorer.Project.ActiveTarget</variable>
+  <value type="int">2</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.EditorSettings</variable>
+  <valuemap type="QVariantMap">
+   <value key="EditorConfiguration.Codec" type="QByteArray">System</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Target.0</variable>
+  <valuemap type="QVariantMap">
+   <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Maemo</value>
+   <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Target.MaemoDeviceTarget</value>
+   <value key="ProjectExplorer.Target.ActiveBuildConfiguration" type="int">1</value>
+   <value key="ProjectExplorer.Target.ActiveRunConfiguration" type="int">0</value>
+   <valuemap key="ProjectExplorer.Target.BuildConfiguration.0" type="QVariantMap">
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.0" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">qmake</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">QtProjectManager.QMakeBuildStep</value>
+     <valuelist key="QtProjectManager.QMakeBuildStep.QMakeArguments" type="QVariantList">
+      <value type="QString">CONFIG+=mobility</value>
+     </valuelist>
+    </valuemap>
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.1" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value>
+     <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">false</value>
+     <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList"/>
+     <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value>
+    </valuemap>
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.2" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MaemoPackageCreationStep</value>
+     <valuelist key="Qt4ProjectManager.BuildStep.MaemoPackage.LocalFiles" type="QVariantList"/>
+     <value key="Qt4ProjectManager.BuildStep.MaemoPackage.Modified" type="bool">true</value>
+     <value key="Qt4ProjectManager.BuildStep.MaemoPackage.RemoteExe" type="QString">/usr/local/bin/movie-schedule</value>
+     <valuelist key="Qt4ProjectManager.BuildStep.MaemoPackage.RemoteFiles" type="QVariantList"/>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.BuildStepsCount" type="int">3</value>
+    <valuemap key="ProjectExplorer.BuildConfiguration.CleanStep.0" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value>
+     <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">true</value>
+     <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList">
+      <value type="QString">clean</value>
+     </valuelist>
+     <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.CleanStepsCount" type="int">1</value>
+    <value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value>
+    <valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/>
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Debug</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration" type="int">2</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory" type="QString">/scratchbox/users/jbecher/home/jbecher/Movies/movie-schedule-arm-debug-madde</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId" type="int">3</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.ToolChain" type="int">9</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild" type="bool">true</value>
+   </valuemap>
+   <valuemap key="ProjectExplorer.Target.BuildConfiguration.1" type="QVariantMap">
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.0" type="QVariantMap">
+     <valuelist key="ProjectExplorer.ProcessStep.Arguments" type="QVariantList">
+      <value type="QString">sb-conf</value>
+      <value type="QString">select</value>
+      <value type="QString">FREMANTLE_ARMEL</value>
+     </valuelist>
+     <value key="ProjectExplorer.ProcessStep.Command" type="QString">/scratchbox/login</value>
+     <value key="ProjectExplorer.ProcessStep.Enabled" type="bool">true</value>
+     <value key="ProjectExplorer.ProcessStep.WorkingDirectory" type="QString">$BUILDDIR</value>
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Select Target</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.ProcessStep</value>
+    </valuemap>
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.1" type="QVariantMap">
+     <valuelist key="ProjectExplorer.ProcessStep.Arguments" type="QVariantList">
+      <value type="QString">-d</value>
+      <value type="QString">Movies/movie-schedule-arm-debug-sdk</value>
+      <value type="QString">qmake</value>
+      <value type="QString">../movie-schedule/movie-schedule.pro</value>
+      <value type="QString">-r</value>
+      <value type="QString">-spec</value>
+      <value type="QString">linux-g++</value>
+      <value type="QString">CONFIG+=maemo_sdk</value>
+      <value type="QString">CONFIG+=debug</value>
+     </valuelist>
+     <value key="ProjectExplorer.ProcessStep.Command" type="QString">/scratchbox/login</value>
+     <value key="ProjectExplorer.ProcessStep.Enabled" type="bool">true</value>
+     <value key="ProjectExplorer.ProcessStep.WorkingDirectory" type="QString">$BUILDDIR</value>
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">QMake</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.ProcessStep</value>
+    </valuemap>
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.2" type="QVariantMap">
+     <valuelist key="ProjectExplorer.ProcessStep.Arguments" type="QVariantList">
+      <value type="QString">-d</value>
+      <value type="QString">Movies/movie-schedule-arm-debug-sdk</value>
+      <value type="QString">make</value>
+      <value type="QString">-w</value>
+     </valuelist>
+     <value key="ProjectExplorer.ProcessStep.Command" type="QString">/scratchbox/login</value>
+     <value key="ProjectExplorer.ProcessStep.Enabled" type="bool">true</value>
+     <value key="ProjectExplorer.ProcessStep.WorkingDirectory" type="QString">$BUILDDIR</value>
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.ProcessStep</value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.BuildStepsCount" type="int">3</value>
+    <valuemap key="ProjectExplorer.BuildConfiguration.CleanStep.0" type="QVariantMap">
+     <valuelist key="ProjectExplorer.ProcessStep.Arguments" type="QVariantList">
+      <value type="QString">-d</value>
+      <value type="QString">Movies/movie-schedule-arm-debug-sdk</value>
+      <value type="QString">make</value>
+      <value type="QString">-w</value>
+      <value type="QString">clean</value>
+     </valuelist>
+     <value key="ProjectExplorer.ProcessStep.Command" type="QString">/scratchbox/login</value>
+     <value key="ProjectExplorer.ProcessStep.Enabled" type="bool">true</value>
+     <value key="ProjectExplorer.ProcessStep.WorkingDirectory" type="QString">$BUILDDIR</value>
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Clean</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.ProcessStep</value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.CleanStepsCount" type="int">1</value>
+    <value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value>
+    <valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/>
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Debug (SDK)</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration" type="int">2</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory" type="QString">/scratchbox/users/jbecher/home/jbecher/Movies/movie-schedule-arm-debug-sdk</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId" type="int">3</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.ToolChain" type="int">9</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild" type="bool">true</value>
+   </valuemap>
+   <value key="ProjectExplorer.Target.BuildConfigurationCount" type="int">2</value>
+   <valuemap key="ProjectExplorer.Target.RunConfiguration.0" type="QVariantMap">
+    <value key=".ProFile" type="QString">src/src.pro</value>
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">N900</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MaemoRunConfiguration</value>
+    <valuelist key="Qt4ProjectManager.MaemoRunConfiguration.Arguments" type="QVariantList"/>
+    <valuemap key="Qt4ProjectManager.MaemoRunConfiguration.DebuggingHelpersLastDeployed" type="QVariantMap"/>
+    <value key="Qt4ProjectManager.MaemoRunConfiguration.DeviceId" type="qulonglong">1</value>
+    <valuemap key="Qt4ProjectManager.MaemoRunConfiguration.LastDeployed" type="QVariantMap"/>
+   </valuemap>
+   <valuemap key="ProjectExplorer.Target.RunConfiguration.1" type="QVariantMap">
+    <value key=".ProFile" type="QString">src/src.pro</value>
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">N900 Emulator</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MaemoRunConfiguration</value>
+    <valuelist key="Qt4ProjectManager.MaemoRunConfiguration.Arguments" type="QVariantList"/>
+    <valuemap key="Qt4ProjectManager.MaemoRunConfiguration.DebuggingHelpersLastDeployed" type="QVariantMap"/>
+    <value key="Qt4ProjectManager.MaemoRunConfiguration.DeviceId" type="qulonglong">9</value>
+    <valuemap key="Qt4ProjectManager.MaemoRunConfiguration.LastDeployed" type="QVariantMap"/>
+   </valuemap>
+   <value key="ProjectExplorer.Target.RunConfigurationCount" type="int">2</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Target.1</variable>
+  <valuemap type="QVariantMap">
+   <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Qt Simulator</value>
+   <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Target.QtSimulatorTarget</value>
+   <value key="ProjectExplorer.Target.ActiveBuildConfiguration" type="int">0</value>
+   <value key="ProjectExplorer.Target.ActiveRunConfiguration" type="int">0</value>
+   <valuemap key="ProjectExplorer.Target.BuildConfiguration.0" type="QVariantMap">
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.0" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">qmake</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">QtProjectManager.QMakeBuildStep</value>
+     <valuelist key="QtProjectManager.QMakeBuildStep.QMakeArguments" type="QVariantList">
+      <value type="QString">CONFIG+=mobility</value>
+     </valuelist>
+    </valuemap>
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.1" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value>
+     <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">false</value>
+     <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList"/>
+     <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.BuildStepsCount" type="int">2</value>
+    <valuemap key="ProjectExplorer.BuildConfiguration.CleanStep.0" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value>
+     <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">true</value>
+     <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList">
+      <value type="QString">clean</value>
+     </valuelist>
+     <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.CleanStepsCount" type="int">1</value>
+    <value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value>
+    <valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/>
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Debug</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration" type="int">2</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory" type="QString">/scratchbox/users/jbecher/home/jbecher/Movies/movie-schedule-x86-debug-simulator</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId" type="int">2</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.ToolChain" type="int">0</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild" type="bool">true</value>
+   </valuemap>
+   <valuemap key="ProjectExplorer.Target.BuildConfiguration.1" type="QVariantMap">
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.0" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">qmake</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">QtProjectManager.QMakeBuildStep</value>
+     <valuelist key="QtProjectManager.QMakeBuildStep.QMakeArguments" type="QVariantList"/>
+    </valuemap>
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.1" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value>
+     <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">false</value>
+     <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList"/>
+     <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.BuildStepsCount" type="int">2</value>
+    <valuemap key="ProjectExplorer.BuildConfiguration.CleanStep.0" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value>
+     <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">true</value>
+     <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList">
+      <value type="QString">clean</value>
+     </valuelist>
+     <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.CleanStepsCount" type="int">1</value>
+    <value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value>
+    <valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/>
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Release</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration" type="int">0</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory" type="QString">/scratchbox/users/jbecher/home/jbecher/Movies/movie-schedule-build-simulator</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId" type="int">2</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.ToolChain" type="int">0</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild" type="bool">true</value>
+   </valuemap>
+   <value key="ProjectExplorer.Target.BuildConfigurationCount" type="int">2</value>
+   <valuemap key="ProjectExplorer.Target.RunConfiguration.0" type="QVariantMap">
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">src</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4RunConfiguration</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.BaseEnvironmentBase" type="int">2</value>
+    <valuelist key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments" type="QVariantList"/>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.ProFile" type="QString">src/src.pro</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix" type="bool">false</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal" type="bool">false</value>
+    <valuelist key="Qt4ProjectManager.Qt4RunConfiguration.UserEnvironmentChanges" type="QVariantList"/>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UserSetName" type="bool">false</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UserSetWorkingDirectory" type="bool">false</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory" type="QString"></value>
+   </valuemap>
+   <value key="ProjectExplorer.Target.RunConfigurationCount" type="int">1</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Target.2</variable>
+  <valuemap type="QVariantMap">
+   <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Desktop</value>
+   <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Target.DesktopTarget</value>
+   <value key="ProjectExplorer.Target.ActiveBuildConfiguration" type="int">0</value>
+   <value key="ProjectExplorer.Target.ActiveRunConfiguration" type="int">0</value>
+   <valuemap key="ProjectExplorer.Target.BuildConfiguration.0" type="QVariantMap">
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.0" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">qmake</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">QtProjectManager.QMakeBuildStep</value>
+     <valuelist key="QtProjectManager.QMakeBuildStep.QMakeArguments" type="QVariantList"/>
+    </valuemap>
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.1" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value>
+     <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">false</value>
+     <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList"/>
+     <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.BuildStepsCount" type="int">2</value>
+    <valuemap key="ProjectExplorer.BuildConfiguration.CleanStep.0" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value>
+     <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">true</value>
+     <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList">
+      <value type="QString">clean</value>
+     </valuelist>
+     <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.CleanStepsCount" type="int">1</value>
+    <value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value>
+    <valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/>
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Debug</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration" type="int">2</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory" type="QString">/scratchbox/users/jbecher/home/jbecher/Movies/movie-schedule-x86-debug-desktop</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId" type="int">8</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.ToolChain" type="int">0</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild" type="bool">true</value>
+   </valuemap>
+   <valuemap key="ProjectExplorer.Target.BuildConfiguration.1" type="QVariantMap">
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.0" type="QVariantMap">
+     <valuelist key="ProjectExplorer.ProcessStep.Arguments" type="QVariantList">
+      <value type="QString">sb-conf</value>
+      <value type="QString">select</value>
+      <value type="QString">FREMANTLE_X86</value>
+     </valuelist>
+     <value key="ProjectExplorer.ProcessStep.Command" type="QString">/scratchbox/login</value>
+     <value key="ProjectExplorer.ProcessStep.Enabled" type="bool">true</value>
+     <value key="ProjectExplorer.ProcessStep.WorkingDirectory" type="QString">$BUILDDIR</value>
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Select Target</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.ProcessStep</value>
+    </valuemap>
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.1" type="QVariantMap">
+     <valuelist key="ProjectExplorer.ProcessStep.Arguments" type="QVariantList">
+      <value type="QString">mkdir</value>
+      <value type="QString">-p</value>
+      <value type="QString">Movies/movie-schedule-x86-debug-sdk</value>
+     </valuelist>
+     <value key="ProjectExplorer.ProcessStep.Command" type="QString">/scratchbox/login</value>
+     <value key="ProjectExplorer.ProcessStep.Enabled" type="bool">true</value>
+     <value key="ProjectExplorer.ProcessStep.WorkingDirectory" type="QString">$BUILDDIR</value>
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Create Builddir</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.ProcessStep</value>
+    </valuemap>
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.2" type="QVariantMap">
+     <valuelist key="ProjectExplorer.ProcessStep.Arguments" type="QVariantList">
+      <value type="QString">-d</value>
+      <value type="QString">Movies/movie-schedule-x86-debug-sdk</value>
+      <value type="QString">qmake</value>
+      <value type="QString">../movie-schedule/movie-schedule.pro</value>
+      <value type="QString">-r</value>
+      <value type="QString">-spec</value>
+      <value type="QString">linux-g++</value>
+      <value type="QString">CONFIG+=maemo_sdk</value>
+      <value type="QString">CONFIG+=debug</value>
+     </valuelist>
+     <value key="ProjectExplorer.ProcessStep.Command" type="QString">/scratchbox/login</value>
+     <value key="ProjectExplorer.ProcessStep.Enabled" type="bool">true</value>
+     <value key="ProjectExplorer.ProcessStep.WorkingDirectory" type="QString">$BUILDDIR</value>
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">QMake</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.ProcessStep</value>
+    </valuemap>
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.3" type="QVariantMap">
+     <valuelist key="ProjectExplorer.ProcessStep.Arguments" type="QVariantList">
+      <value type="QString">-d</value>
+      <value type="QString">Movies/movie-schedule-x86-debug-sdk</value>
+      <value type="QString">make</value>
+      <value type="QString">-w</value>
+     </valuelist>
+     <value key="ProjectExplorer.ProcessStep.Command" type="QString">/scratchbox/login</value>
+     <value key="ProjectExplorer.ProcessStep.Enabled" type="bool">true</value>
+     <value key="ProjectExplorer.ProcessStep.WorkingDirectory" type="QString">$BUILDDIR</value>
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.ProcessStep</value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.BuildStepsCount" type="int">4</value>
+    <valuemap key="ProjectExplorer.BuildConfiguration.CleanStep.0" type="QVariantMap">
+     <valuelist key="ProjectExplorer.ProcessStep.Arguments" type="QVariantList">
+      <value type="QString">-d</value>
+      <value type="QString">Movies/movie-schedule-x86-debug-sdk</value>
+      <value type="QString">make</value>
+      <value type="QString">-w</value>
+      <value type="QString">clean</value>
+     </valuelist>
+     <value key="ProjectExplorer.ProcessStep.Command" type="QString">/scratchbox/login</value>
+     <value key="ProjectExplorer.ProcessStep.Enabled" type="bool">true</value>
+     <value key="ProjectExplorer.ProcessStep.WorkingDirectory" type="QString">$BUILDDIR</value>
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Clean</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.ProcessStep</value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.CleanStepsCount" type="int">1</value>
+    <value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value>
+    <valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/>
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Debug (SDK)</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration" type="int">2</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory" type="QString">/scratchbox/users/jbecher/home/jbecher/Movies/movie-schedule-x86-debug-sdk</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId" type="int">8</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.ToolChain" type="int">0</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild" type="bool">true</value>
+   </valuemap>
+   <valuemap key="ProjectExplorer.Target.BuildConfiguration.2" type="QVariantMap">
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.0" type="QVariantMap">
+     <valuelist key="ProjectExplorer.ProcessStep.Arguments" type="QVariantList">
+      <value type="QString">/scratchbox/users/jbecher/home/jbecher/Movies/movie-schedule/movie-schedule.pro</value>
+     </valuelist>
+     <value key="ProjectExplorer.ProcessStep.Command" type="QString">lupdate</value>
+     <value key="ProjectExplorer.ProcessStep.Enabled" type="bool">true</value>
+     <value key="ProjectExplorer.ProcessStep.WorkingDirectory" type="QString">$BUILDDIR</value>
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">LUpdate</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.ProcessStep</value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.BuildStepsCount" type="int">1</value>
+    <value key="ProjectExplorer.BuildConfiguration.CleanStepsCount" type="int">0</value>
+    <value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value>
+    <valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/>
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">LUpdate</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration" type="int">2</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory" type="QString">/scratchbox/users/jbecher/home/jbecher/Movies/movie-schedule-lupdate</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId" type="int">8</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.ToolChain" type="int">0</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild" type="bool">true</value>
+   </valuemap>
+   <value key="ProjectExplorer.Target.BuildConfigurationCount" type="int">3</value>
+   <valuemap key="ProjectExplorer.Target.RunConfiguration.0" type="QVariantMap">
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">src</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4RunConfiguration</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.BaseEnvironmentBase" type="int">2</value>
+    <valuelist key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments" type="QVariantList"/>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.ProFile" type="QString">src/src.pro</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix" type="bool">false</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal" type="bool">false</value>
+    <valuelist key="Qt4ProjectManager.Qt4RunConfiguration.UserEnvironmentChanges" type="QVariantList"/>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UserSetName" type="bool">false</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UserSetWorkingDirectory" type="bool">false</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory" type="QString"></value>
+   </valuemap>
+   <value key="ProjectExplorer.Target.RunConfigurationCount" type="int">1</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.TargetCount</variable>
+  <value type="int">3</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
+  <value type="int">4</value>
+ </data>
+</qtcreator>
diff --git a/src/control/actioncontroller.cpp b/src/control/actioncontroller.cpp
new file mode 100644 (file)
index 0000000..3d74247
--- /dev/null
@@ -0,0 +1,228 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "actioncontroller.h"
+
+#include "data/cinemaschedule.h"
+#include "data/scheduleentry.h"
+#include "data/cinema.h"
+#include "data/movie.h"
+#include "ui/uiutils.h"
+#include "utils/calendar.h"
+#include "utils/timeutils.h"
+#include "utils/assertedlocker.h"
+
+#include <QtDBus>
+#include <QUrl>
+#include <QDesktopServices>
+#include <iostream>
+
+ActionController::ActionController(const CinemaSchedule *cinema_schedule) :
+        QObject(0),
+        _cinema_schedule(cinema_schedule)
+{
+}
+
+void ActionController::AddToCalendar(ScheduleEntryKey schedule_entry_key)
+{
+#ifdef MAEMO_SDK
+    ScheduleEntry schedule_entry;
+    Movie movie;
+    Cinema cinema;
+    {
+        AssertedReadLocker locker(_cinema_schedule->GetLock());
+        schedule_entry = _cinema_schedule->FindScheduleEntry(schedule_entry_key);
+        if (schedule_entry.IsValid()) {
+            movie = *schedule_entry.GetMovie();
+            cinema = *schedule_entry.GetCinema();
+        }
+    }
+    if (schedule_entry.IsValid()) {
+        Calendar calendar(this);
+        QDateTime start_time;
+        start_time.setDate(schedule_entry.GetDate());
+        start_time.setTime(schedule_entry.GetStartTime());
+        int minutes = movie.GetDuration().hour() * 60
+                      + movie.GetDuration().minute();
+        minutes = ((minutes + 14) / 15) * 15;
+        QDateTime end_time = start_time.addSecs(minutes * 60);
+        QString location = cinema.GetName();
+        QString description;
+        if (!cinema.GetAddress().isEmpty()) {
+            if (!location.isEmpty()) {
+                location += ", ";
+            }
+            location += cinema.GetAddress();
+        }
+        if (!cinema.GetTelephone().isEmpty()) {
+            if (!description.isEmpty()) {
+                description += "\n";
+            }
+            description += cinema.GetTelephone();
+        }
+        if (!calendar.AddEvent(movie.GetName(), start_time, end_time,
+                               location, description)) {
+            ShowError(tr("Adding calendar event failed."));
+            return;
+        }
+        UiUtils::ShowInformation(
+                tr("%1 (%2 %3) added to your calendar.")
+                .arg(movie.GetName())
+                .arg(TimeUtils::ToDateString(schedule_entry.GetDate()))
+                .arg(TimeUtils::ToTimeString(schedule_entry.GetStartTime())));
+    } else {
+        ShowError(tr("Adding calendar event failed."));
+    }
+#else
+    Q_UNUSED(schedule_entry_key);
+    ShowError(tr("Adding calendar event failed."));
+#endif
+}
+
+void ActionController::CallTheaterByPhone(CinemaKey cinema_key)
+{
+    Cinema cinema;
+    {
+        AssertedReadLocker locker(_cinema_schedule->GetLock());
+        const Cinema *cinema_p = _cinema_schedule->FindCinema(cinema_key);
+        if (cinema_p != 0) {
+            cinema = *cinema_p;
+        }
+    }
+    if (cinema.IsValid()) {
+        if (!cinema.GetTelephone().isEmpty()) {
+            if (!QDBusConnection::systemBus().isConnected()) {
+                ShowError(tr("Unable to call theater by phone: communication bus not available."));
+                return;
+            }
+            QDBusInterface iface("com.nokia.csd.Call", "/com/nokia/csd/call", "com.nokia.csd.Call", QDBusConnection::systemBus());
+            if (!iface.isValid()) {
+                ShowError(tr("Unable to call theater by phone: phone service not available."));
+                return;
+            }
+            QString phone_number = TrimPhoneNumber(cinema.GetTelephone());
+            QDBusReply<QDBusObjectPath> reply = iface.call("CreateWith", phone_number, 0);
+            if (!reply.isValid()) {
+                std::cout << qPrintable(reply.error().message()) << ": <" << qPrintable(phone_number) << ">" << std::endl;
+                ShowError(tr("Unable to call theater by phone: call failed."));
+                return;
+            }
+        }
+    }
+}
+
+void ActionController::FindRouteToTheater(CinemaKey cinema_key)
+{
+    Cinema cinema;
+    {
+        AssertedReadLocker locker(_cinema_schedule->GetLock());
+        const Cinema *cinema_p = _cinema_schedule->FindCinema(cinema_key);
+        if (cinema_p != 0) {
+            cinema = *cinema_p;
+        }
+    }
+    if (cinema.IsValid()) {
+        // TODO implement find route to theater
+    }
+}
+
+void ActionController::SearchTheaterInWeb(CinemaKey cinema_key)
+{
+    QString key;
+    {
+        AssertedReadLocker locker(_cinema_schedule->GetLock());
+        const Cinema *cinema = _cinema_schedule->FindCinema(cinema_key);
+        if (cinema != 0) {
+            key = cinema->GetName() + " " + cinema->GetAddress();
+        }
+    }
+    if (!key.isEmpty()) {
+        SearchInWeb(key);
+    }
+}
+
+void ActionController::SearchMovieInWeb(MovieKey movie_key)
+{
+    QString key;
+    {
+        AssertedReadLocker locker(_cinema_schedule->GetLock());
+        const Movie *movie = _cinema_schedule->FindMovie(movie_key);
+        if (movie != 0) {
+            key = movie->GetName();
+        }
+    }
+    if (!key.isEmpty()) {
+        SearchInWeb(key);
+    }
+}
+
+void ActionController::ContactAuthor()
+{
+    QUrl url("mailto::Jochen Becher <j.becher@ovi.com>", QUrl::TolerantMode);
+    url.addQueryItem("subject", "Application 'MovieSchedule' for Nokia N900");
+    QDesktopServices::openUrl(url);
+}
+
+QString ActionController::TrimPhoneNumber(const QString &phone_number)
+{
+    QString trimmed;
+    bool plus_is_valid = true;
+    foreach (QChar ch, phone_number) {
+        switch (ch.toAscii()) {
+        case ',':
+        case '.':
+        case '(':
+        case ')':
+        case '-':
+        case ' ':
+        case '\t':
+        case '/':
+            // trim character
+            break;
+        case 'p':
+        case 'w':
+        case 'x':
+            trimmed += ch.toUpper();
+            break;
+        case '+':
+            if (plus_is_valid) {
+                trimmed += ch;
+            }
+            break;
+        default:
+            trimmed += ch;
+        }
+        // TODO plus_is_valid stays true as long as we are parsing a number suppression prefix (e.g. *31#)
+        plus_is_valid = false;
+    }
+    return trimmed;
+}
+
+void ActionController::SearchInWeb(const QString &key)
+{
+    QUrl url("http://www.google.com/search");
+    url.addQueryItem("q", key);
+    if (!QDesktopServices::openUrl(url)) {
+        ShowError(tr("Unable to search in web: browser service not available."));
+        return;
+    }
+}
+
+void ActionController::ShowError(const QString &msg)
+{
+    UiUtils::ShowError(msg);
+}
diff --git a/src/control/actioncontroller.h b/src/control/actioncontroller.h
new file mode 100644 (file)
index 0000000..9c593b9
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef ACTIONCONTROLLER_H
+#define ACTIONCONTROLLER_H
+
+#include "data/cinemakey.h"
+#include "data/moviekey.h"
+#include "data/scheduleentrykey.h"
+
+#include <QObject>
+
+class CinemaSchedule;
+
+class ActionController : public QObject
+{
+    Q_OBJECT
+public:
+    explicit ActionController(const CinemaSchedule *cinema_schedule);
+
+public:
+    Q_SLOT void AddToCalendar(ScheduleEntryKey);
+    Q_SLOT void CallTheaterByPhone(CinemaKey);
+    Q_SLOT void FindRouteToTheater(CinemaKey);
+    Q_SLOT void SearchTheaterInWeb(CinemaKey);
+    Q_SLOT void SearchMovieInWeb(MovieKey);
+    Q_SLOT void ContactAuthor();
+
+private:
+    QString TrimPhoneNumber(const QString &phone_number);
+    void SearchInWeb(const QString &key);
+    void ShowError(const QString &);
+
+private:
+    const CinemaSchedule *_cinema_schedule;
+};
+
+#endif // ACTIONCONTROLLER_H
diff --git a/src/control/itemmodelsortclient.cpp b/src/control/itemmodelsortclient.cpp
new file mode 100644 (file)
index 0000000..efa8775
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "itemmodelsortclient.h"
+
+#include "itemmodelsortproxy.h"
+#include "itemmodelsortcontroller.h"
+
+#include <iostream>
+
+ItemModelSortClient::ItemModelSortClient(ItemModelSortController *controller, QObject *parent)
+    : QObject(parent),
+    _proxy(new ItemModelSortProxy(controller)),
+    _model(0),
+    _task_id(0),
+    _intermediate(false)
+{
+    connect(this, SIGNAL(Sort(QAbstractItemModel*)), _proxy, SLOT(Sort(QAbstractItemModel*)));
+    connect(_proxy, SIGNAL(SortFinished(QAbstractItemModel*)), this, SLOT(SortFinished(QAbstractItemModel*)));
+    _proxy->moveToThread(controller->thread());
+}
+
+void ItemModelSortClient::Sort(QAbstractItemModel *model, int task_id, bool intermediate)
+{
+    _model = model;
+    _task_id = task_id;
+    _intermediate = intermediate;
+    //std::cout << "Start sorting model " << model << " with intermediate = " << intermediate << std::endl;
+    emit Sort(model);
+}
+
+void ItemModelSortClient::SortFinished(QAbstractItemModel *model)
+{
+    //std::cout << "Finished sorting model " << model << " with intermediate = " << _intermediate << std::endl;
+    emit SortFinished(model, _task_id, _intermediate);
+    deleteLater();
+}
diff --git a/src/control/itemmodelsortclient.h b/src/control/itemmodelsortclient.h
new file mode 100644 (file)
index 0000000..ba96f5d
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef ITEMMODELSORTCLIENT_H
+#define ITEMMODELSORTCLIENT_H
+
+#include <QObject>
+
+class ItemModelSortController;
+class QAbstractItemModel;
+class ItemModelSortProxy;
+
+class ItemModelSortClient : public QObject
+{
+    Q_OBJECT
+public:
+    explicit ItemModelSortClient(ItemModelSortController *, QObject *parent = 0);
+
+public:
+    void Sort(QAbstractItemModel *model, int task_id, bool intermediate);
+
+public:
+    Q_SIGNAL void SortFinished(QAbstractItemModel *model, int task_id, bool intermediate);
+
+private:
+    Q_SLOT void SortFinished(QAbstractItemModel *model);
+
+private:
+    Q_SIGNAL void Sort(QAbstractItemModel *);
+
+private:
+    ItemModelSortProxy *_proxy;
+    QAbstractItemModel *_model;
+    int _task_id;
+    bool _intermediate;
+};
+
+#endif // ITEMMODELSORTCLIENT_H
diff --git a/src/control/itemmodelsortcontroller.cpp b/src/control/itemmodelsortcontroller.cpp
new file mode 100644 (file)
index 0000000..cef92b8
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "itemmodelsortcontroller.h"
+
+#include "data/cinemaschedule.h"
+#include "utils/assertedlocker.h"
+
+#include <QAbstractItemModel>
+#include <QThread>
+
+ItemModelSortController::ItemModelSortController(CinemaSchedule *cinema_schedule)
+    : _cinema_schedule(cinema_schedule)
+{
+}
+
+void ItemModelSortController::Sort(QAbstractItemModel *model)
+{
+    AssertedReadLocker(_cinema_schedule->GetLock());
+    model->sort(0);
+    //sleep(2);
+}
diff --git a/src/control/itemmodelsortcontroller.h b/src/control/itemmodelsortcontroller.h
new file mode 100644 (file)
index 0000000..844edec
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef ITEMMODELSORTCONTROLLER_H
+#define ITEMMODELSORTCONTROLLER_H
+
+#include <QObject>
+
+class CinemaSchedule;
+class QAbstractItemModel;
+
+class ItemModelSortController : public QObject
+{
+    Q_OBJECT
+public:
+    ItemModelSortController(CinemaSchedule *cinema_schedule);
+
+public:
+    void Sort(QAbstractItemModel *model);
+
+private:
+    CinemaSchedule *_cinema_schedule;
+};
+
+#endif // ITEMMODELSORTCONTROLLER_H
diff --git a/src/control/itemmodelsortproxy.cpp b/src/control/itemmodelsortproxy.cpp
new file mode 100644 (file)
index 0000000..03dbd1e
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "itemmodelsortproxy.h"
+
+#include "itemmodelsortcontroller.h"
+
+ItemModelSortProxy::ItemModelSortProxy(ItemModelSortController *controller)
+    : _controller(controller)
+{
+}
+
+void ItemModelSortProxy::Sort(QAbstractItemModel *model)
+{
+    _controller->Sort(model);
+    emit SortFinished(model);
+    deleteLater();
+}
diff --git a/src/control/itemmodelsortproxy.h b/src/control/itemmodelsortproxy.h
new file mode 100644 (file)
index 0000000..b6fd8ee
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef ITEMMODELSORTPROXY_H
+#define ITEMMODELSORTPROXY_H
+
+#include <QObject>
+
+class ItemModelSortController;
+class QAbstractItemModel;
+
+class ItemModelSortProxy : public QObject
+{
+    Q_OBJECT
+public:
+    ItemModelSortProxy(ItemModelSortController *);
+
+public:
+    Q_SLOT void Sort(QAbstractItemModel *model);
+
+public:
+    Q_SIGNAL void SortFinished(QAbstractItemModel *model);
+
+private:
+    ItemModelSortController *_controller;
+};
+
+#endif // ITEMMODELSORTPROXY_H
diff --git a/src/control/locationcontroller.cpp b/src/control/locationcontroller.cpp
new file mode 100644 (file)
index 0000000..65b2541
--- /dev/null
@@ -0,0 +1,171 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "locationcontroller.h"
+
+#include "ui/locationdialog.h"
+#include "searchclients/gpsclient.h"
+#include "data/settings.h"
+#include "ui/mainwindow.h"
+
+static const char *MSG_LOCATION_NOT_FOUND = QT_TRANSLATE_NOOP("LocationController", "Unable to detect current city.");
+
+LocationController::LocationController(MainWindow *main_window, Settings *settings) :
+    QObject(0),
+    _main_window(main_window),
+    _settings(settings),
+    _active_search_task_id(GpsClient::INVALID_SEARCH_TASK_ID)
+{
+}
+
+void LocationController::OpenLocationDialog()
+{
+    LocationDialog *location_dialog = new LocationDialog(_main_window);
+    connect(location_dialog, SIGNAL(Search(Location)), this, SLOT(SearchLocationFromCityDatabase(Location)));
+    connect(location_dialog, SIGNAL(SearchPreviousLocation(Location)), this, SLOT(SearchLocation(Location)));
+    connect(location_dialog, SIGNAL(SearchGPS()), this, SLOT(SearchGPS()));
+    connect(location_dialog, SIGNAL(Cancel()), this, SLOT(CancelLocation()));
+    location_dialog->SetLocation(_settings->GetLocation());
+    location_dialog->SetPreviousLocations(_settings->GetPreviousLocations());
+    location_dialog->SetGPSEnabled(true || _settings->IsGPSEnabled());
+    location_dialog->show();
+    // location_dialog deletes itself
+}
+
+void LocationController::CancelAllGpsSearchs()
+{
+    _active_search_task_id = GpsClient::INVALID_SEARCH_TASK_ID;
+    GpsClient::CancelAllRunningSearchs();
+}
+
+void LocationController::SearchLocationFromCityDatabase(Location location)
+{
+    // TODO check city database
+    SearchLocation(location);
+}
+
+void LocationController::SearchLocation(Location location)
+{
+    location = CleanLocation(location);
+    RememberLocation(location);
+    emit Search(location);
+}
+
+void LocationController::SearchGPS()
+{
+    GpsClient *client = new GpsClient();
+    connect(client, SIGNAL(SearchStarted(int)), this, SLOT(GpsSearchStarted(int)));
+    connect(client, SIGNAL(PositionUpdate(int)), this, SLOT(GpsPositionUpdate(int)));
+    connect(client, SIGNAL(SearchForTownStarted(int)), this, SLOT(GpsSearchForTownStarted(int)));
+    connect(client, SIGNAL(TownUpdate(int,QString)), this, SLOT(GpsTownUpdate(int,QString)));
+    connect(client, SIGNAL(SearchError(int)), this, SLOT(GpsSearchError(int)));
+    connect(client, SIGNAL(SearchFinished(int,bool)), this, SLOT(GpsSearchFinished(int,bool)));
+    _active_search_task_id = client->GetSearchTaskId();
+    client->SearchLocation();
+    // gps client deletes itself
+}
+
+void LocationController::CancelLocation()
+{
+    // nothing to do
+}
+
+Location LocationController::CleanLocation(const Location &location)
+{
+    // TODO clash with city database?
+    QString name = location.GetLocationName().trimmed();
+    if (name.size() > 0) {
+        if (name[0].isLower()) {
+            name[0] = name[0].toUpper();
+        }
+    }
+    Location cleaned_location;
+    cleaned_location.SetLocationName(name);
+    return cleaned_location;
+}
+
+void LocationController::RememberLocation(const Location &location)
+{
+    if (!location.IsValid()) {
+        return;
+    }
+    Settings::Locations locations = _settings->GetPreviousLocations();
+    QMutableListIterator<Location> it(locations);
+    while (it.hasNext()) {
+        const Location &prev_location = it.next();
+        if (prev_location == location) {
+            it.remove();
+        }
+    }
+    locations.push_front(location);
+    while (locations.size() > 5) {
+        locations.pop_back();
+    }
+    _settings->SetPreviousLocations(locations);
+}
+
+void LocationController::GpsSearchStarted(int search_task_id)
+{
+    if (_active_search_task_id != search_task_id) {
+        return;
+    }
+    _main_window->SetBusy(true);
+}
+
+void LocationController::GpsPositionUpdate(int search_task_id)
+{
+    if (_active_search_task_id != search_task_id) {
+        return;
+    }
+}
+
+void LocationController::GpsSearchForTownStarted(int search_task_id)
+{
+    if (_active_search_task_id != search_task_id) {
+        return;
+    }
+}
+
+void LocationController::GpsTownUpdate(int search_task_id, QString town)
+{
+    if (_active_search_task_id != search_task_id) {
+        return;
+    }
+    Location location;
+    location.SetLocationName(town);
+    SearchLocation(location);
+}
+
+void LocationController::GpsSearchError(int search_task_id)
+{
+    if (_active_search_task_id != search_task_id) {
+        return;
+    }
+    _main_window->SetError(tr(MSG_LOCATION_NOT_FOUND));
+}
+
+void LocationController::GpsSearchFinished(int search_task_id, bool success)
+{
+    if (_active_search_task_id != search_task_id) {
+        return;
+    }
+    // In case of success SearchLocation() is started which will
+    // unset busy state on its end
+    if (!success) {
+        _main_window->SetBusy(false);
+    }
+}
diff --git a/src/control/locationcontroller.h b/src/control/locationcontroller.h
new file mode 100644 (file)
index 0000000..a1ffbb2
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef LOCATIONCONTROLLER_H
+#define LOCATIONCONTROLLER_H
+
+#include "data/location.h"
+
+#include <QObject>
+
+class MainWindow;
+class Settings;
+
+class LocationController : public QObject
+{
+    Q_OBJECT
+public:
+    explicit LocationController(MainWindow *main_window, Settings *settings);
+
+public:
+    Q_SLOT void OpenLocationDialog();
+
+    void CancelAllGpsSearchs();
+
+public:
+    Q_SIGNAL void Search(Location location);
+
+private:
+    Q_SLOT void SearchLocationFromCityDatabase(Location location);
+    Q_SLOT void SearchLocation(Location location);
+    Q_SLOT void SearchGPS();
+    Q_SLOT void CancelLocation();
+    Location CleanLocation(const Location &location);
+    void RememberLocation(const Location &location);
+
+    Q_SLOT void GpsSearchStarted(int search_task_id);
+    Q_SLOT void GpsPositionUpdate(int search_task_id);
+    Q_SLOT void GpsSearchForTownStarted(int search_task_id);
+    Q_SLOT void GpsTownUpdate(int search_task_id, QString town);
+    Q_SLOT void GpsSearchError(int search_task_id);
+    Q_SLOT void GpsSearchFinished(int search_task_id, bool success);
+
+private:
+    MainWindow *_main_window;
+    Settings *_settings;
+    int _active_search_task_id;
+};
+
+#endif // LOCATIONCONTROLLER_H
diff --git a/src/control/maincontroller.cpp b/src/control/maincontroller.cpp
new file mode 100644 (file)
index 0000000..5130da7
--- /dev/null
@@ -0,0 +1,386 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "maincontroller.h"
+
+#include "data/settings.h"
+#include "data/cinemaschedule.h"
+#include "data/movie.h"
+#include "data/cinema.h"
+#include "control/theatercontroller.h"
+#include "control/moviecontroller.h"
+#include "control/actioncontroller.h"
+#include "control/locationcontroller.h"
+#include "control/itemmodelsortclient.h"
+#include "ui/aboutdialog.h"
+#include "ui/mainwindow.h"
+#include "ui/theatermodel.h"
+#include "ui/moviemodel.h"
+#include "ui/uiutils.h"
+#include "searchclients/theatersearchclient.h"
+#include "searchclients/moviesearchclient.h"
+#include "utils/assertedlocker.h"
+#include "utils/asynccall.h"
+#include "utils/connectivitymanager.h"
+
+#include <QSortFilterProxyModel>
+#include <iostream>
+
+static const char *MSG_NETWORK_ERROR = QT_TRANSLATE_NOOP("MainController", "Unable to access network.");
+static const char *MSG_NO_THEATERS_FOUND = QT_TRANSLATE_NOOP("MainController", "No theaters found near %1.");
+static const char *MSG_NO_MOVIES_FOUND = QT_TRANSLATE_NOOP("MainController", "No movies found near %1.");
+static const char *MSG_THEATERS_ERROR = QT_TRANSLATE_NOOP("MainController", "Error on fetching theaters.");
+static const char *MSG_MOVIES_ERROR = QT_TRANSLATE_NOOP("MainController", "Error on fetching movies.");
+
+MainController::MainController(MainWindow *main_window, Settings *settings, CinemaSchedule *cinema_schedule,
+                               TheaterController *theater_controller,
+                               MovieController *movie_controller,
+                               LocationController *location_controller,
+                               ActionController *action_controller,
+                               ItemModelSortController *sort_controller,
+                               QThread *search_worker)
+                                   : _main_window(main_window),
+                                   _settings(settings),
+                                   _cinema_schedule(cinema_schedule),
+                                   _theater_controller(theater_controller),
+                                   _movie_controller(movie_controller),
+                                   _location_controller(location_controller),
+                                   _action_controller(action_controller),
+                                   _sort_controller(sort_controller),
+                                   _search_worker(search_worker),
+                                   _connectivity_manager(new ConnectivityManager(this)),
+                                   _current_theater_search_task_id(TheaterSearchClient::INVALID_SEARCH_TASK_ID),
+                                   _current_movies_search_task_id(MovieSearchClient::INVALID_SEARCH_TASK_ID),
+                                   _theater_model(new TheaterModel(cinema_schedule, this)),
+                                   _movie_model(new MovieModel(cinema_schedule, this)),
+                                   _theater_proxy_model(new QSortFilterProxyModel(this)),
+                                   _movie_proxy_model(new QSortFilterProxyModel(this)),
+                                   _last_search_settings()
+{
+    connect(_main_window, SIGNAL(SearchTheaters()), this, SLOT(SearchTheaters()));
+    connect(_main_window, SIGNAL(SearchMovies()), this, SLOT(SearchMovies()));
+    connect(_main_window, SIGNAL(TheaterSelected(CinemaKey)), _theater_controller, SLOT(ShowTheater(CinemaKey)));
+    connect(_main_window, SIGNAL(CallTheaterByPhone(CinemaKey)), _action_controller, SLOT(CallTheaterByPhone(CinemaKey)));
+    connect(_main_window, SIGNAL(FindRouteToTheater(CinemaKey)), _action_controller, SLOT(FindRouteToTheater(CinemaKey)));
+    connect(_main_window, SIGNAL(SearchTheaterInWeb(CinemaKey)), _action_controller, SLOT(SearchTheaterInWeb(CinemaKey)));
+    connect(_main_window, SIGNAL(MovieSelected(MovieKey)), _movie_controller, SLOT(ShowMovie(MovieKey)));
+    connect(_main_window, SIGNAL(SearchMovieInWeb(MovieKey)), _action_controller, SLOT(SearchMovieInWeb(MovieKey)));
+    connect(_main_window, SIGNAL(OpenLocationDialog()), _location_controller, SLOT(OpenLocationDialog()));
+    connect(_main_window, SIGNAL(OpenAboutDialog()), this, SLOT(OpenAboutDialog()));
+    connect(_location_controller, SIGNAL(Search(Location)), this, SLOT(Search(Location)));
+    connect(_connectivity_manager, SIGNAL(Connected()), this, SLOT(NetworkConnected()));
+    connect(_connectivity_manager, SIGNAL(Disconnected()), this, SLOT(NetworkDisconnected()));
+    connect(_connectivity_manager, SIGNAL(Error()), this, SLOT(NetworkError()));
+}
+
+MainController::~MainController()
+{
+}
+
+void MainController::Run()
+{
+    _connectivity_manager->Connect();
+}
+
+void MainController::Search()
+{
+    _location_controller->CancelAllGpsSearchs();
+    // TODO add some timer condition? How old are the loaded information
+    if (_settings->GetLocation() != _last_search_settings.GetLocation()) {
+        CancelTheaterSearch();
+        CancelMovieSearch();
+        _movie_controller->Cancel();
+        _theater_controller->Cancel();
+        AssertedWriteLocker locker(_cinema_schedule->GetLock());
+        _cinema_schedule->Clear();
+    }
+    if (_settings->GetLocation().IsValid()) {
+        // Cancel searchs before _cinema_schedule is locked to avoid dead-locks
+        switch (_settings->GetSearchObjectsType()) {
+        case Settings::THEATERS:
+            CancelTheaterSearch();
+            break;
+        case Settings::MOVIES:
+            CancelMovieSearch();
+            break;
+        }
+        AssertedReadLocker locker(_cinema_schedule->GetLock());
+        _main_window->SetLocation(_settings->GetLocation());
+        switch (_settings->GetSearchObjectsType()) {
+        case Settings::THEATERS:
+            _main_window->SetTheaterModel(_theater_proxy_model);
+            if (!_cinema_schedule->AreAllCinemasLoaded()) {
+                TheaterSearchClient *client = new TheaterSearchClient(_cinema_schedule);
+                _current_theater_search_task_id = client->GetSearchTaskId();
+                connect(client, SIGNAL(SearchStarted(int)), this, SLOT(TheatersSearchStarted(int)));
+                connect(client, SIGNAL(Reply(int, bool)), this, SLOT(TheatersSearchReply(int, bool)));
+                connect(client, SIGNAL(Error(int)), this, SLOT(TheatersSearchError(int)));
+                connect(client, SIGNAL(SearchFinished(int, bool)), this, SLOT(TheatersSearchFinished(int, bool)));
+                client->moveToThread(_search_worker);
+                CallAsync(client, &TheaterSearchClient::SearchTheater, _settings->GetLocation().GetLocationName());
+            } else {
+                TheatersSearchStarted(_current_theater_search_task_id);
+                TheatersSearchReply(_current_theater_search_task_id, true);
+                TheatersSearchFinished(_current_theater_search_task_id, true);
+            }
+            break;
+        case Settings::MOVIES:
+            _main_window->SetMovieModel(_movie_proxy_model);
+            if (!_cinema_schedule->AreAllMoviesLoaded()) {
+                MovieSearchClient *client = new MovieSearchClient(_cinema_schedule);
+                _current_movies_search_task_id = client->GetSearchTaskId();
+                connect(client, SIGNAL(SearchStarted(int)), this, SLOT(MoviesSearchStarted(int)));
+                connect(client, SIGNAL(Reply(int, bool)), this, SLOT(MoviesSearchReply(int, bool)));
+                connect(client, SIGNAL(Error(int)), this, SLOT(MoviesSearchError(int)));
+                connect(client, SIGNAL(SearchFinished(int, bool)), this, SLOT(MoviesSearchFinished(int, bool)));
+                client->moveToThread(_search_worker);
+                CallAsync(client, &MovieSearchClient::SearchMovie, _settings->GetLocation().GetLocationName());
+            } else {
+                MoviesSearchStarted(_current_movies_search_task_id);
+                MoviesSearchReply(_current_movies_search_task_id, true);
+                MoviesSearchFinished(_current_movies_search_task_id, true);
+            }
+            break;
+        }
+        _last_search_settings = *_settings;
+    } else {
+        _location_controller->OpenLocationDialog();
+    }
+}
+
+void MainController::Search(Location location)
+{
+    _settings->SetLocation(location);
+    Search();
+}
+
+void MainController::NetworkConnected()
+{
+    Search();
+}
+
+void MainController::NetworkDisconnected()
+{
+}
+
+void MainController::NetworkError()
+{
+    _main_window->SetError(tr(MSG_NETWORK_ERROR));
+}
+
+void MainController::SearchTheaters()
+{
+    _settings->SetSearchObjectsType(Settings::THEATERS);
+    Search();
+}
+
+void MainController::SearchMovies()
+{
+    _settings->SetSearchObjectsType(Settings::MOVIES);
+    Search();
+}
+
+void MainController::OpenAboutDialog()
+{
+    AboutDialog *about_dialog = new AboutDialog(_main_window);
+    connect(about_dialog, SIGNAL(ContactAuthor()), _action_controller, SLOT(ContactAuthor()));
+    about_dialog->show();
+    // dialog deletes itself
+}
+
+void MainController::CancelTheaterSearch()
+{
+    AssertedWriteLocker locker(_cinema_schedule->GetLock());
+    _current_theater_search_task_id = TheaterSearchClient::INVALID_SEARCH_TASK_ID;
+    TheaterSearchClient::CancelAllRunningSearchs();
+}
+
+void MainController::CancelMovieSearch()
+{
+    AssertedWriteLocker locker(_cinema_schedule->GetLock());
+    _current_movies_search_task_id = MovieSearchClient::INVALID_SEARCH_TASK_ID;
+    MovieSearchClient::CancelAllRunningSearchs();
+}
+
+void MainController::TheatersSearchStarted(int search_task_id)
+{
+    if (search_task_id != _current_theater_search_task_id) {
+        return;
+    }
+    _main_window->SetBusy(true);
+    SortTheaters(true, SLOT(TheatersSortFinished(QAbstractItemModel*,int,bool)));
+}
+
+void MainController::TheatersSearchReply(int search_task_id, bool intermediate)
+{
+    if (search_task_id != _current_theater_search_task_id) {
+        return;
+    }
+    SortTheaters(intermediate, SLOT(TheatersSortFinished(QAbstractItemModel*,int,bool)));
+}
+
+void MainController::TheatersSearchError(int search_task_id)
+{
+    if (search_task_id != _current_theater_search_task_id) {
+        return;
+    }
+    SortTheaters(false, SLOT(TheatersSortErrorFinished(QAbstractItemModel*,int,bool)));
+}
+
+void MainController::TheatersSearchFinished(int search_task_id, bool success)
+{
+    Q_UNUSED(success);
+    if (search_task_id != _current_theater_search_task_id) {
+        return;
+    }
+    _main_window->SetBusy(false);
+}
+
+void MainController::SortTheaters(bool intermediate, const char *slot)
+{
+    TheaterModel *theater_model = new TheaterModel(_cinema_schedule, this);
+    QSortFilterProxyModel *sort_model = new QSortFilterProxyModel(this);
+    sort_model->setSortCaseSensitivity(Qt::CaseInsensitive);
+    sort_model->setSortRole(TheaterModel::SortRole);
+    sort_model->setDynamicSortFilter(false);
+    sort_model->setSourceModel(theater_model);
+    ItemModelSortClient *sort_client = new ItemModelSortClient(_sort_controller, this);
+    connect(sort_client, SIGNAL(SortFinished(QAbstractItemModel*,int,bool)), this, slot);
+    sort_client->Sort(sort_model, _current_theater_search_task_id, intermediate);
+    // proxy deletes itself
+}
+
+void MainController::TheatersSortFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
+{
+    if (search_task_id != _current_theater_search_task_id) {
+        return;
+    }
+    SetTheaterModel(model);
+    if (!intermediate) {
+        AssertedWriteLocker locker(_cinema_schedule->GetLock());
+        _cinema_schedule->SetAllCinemasLoaded(true);
+        if (_theater_model->rowCount() == 0) {
+            _main_window->SetError(tr(MSG_NO_THEATERS_FOUND).arg(_settings->GetLocation().GetLocationName()));
+        }
+    }
+}
+
+void MainController::TheatersSortErrorFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
+{
+    Q_UNUSED(intermediate);
+    if (search_task_id != _current_theater_search_task_id) {
+        return;
+    }
+    SetTheaterModel(model);
+    if (_theater_model->rowCount() == 0) {
+        _main_window->SetError(tr(MSG_THEATERS_ERROR));
+    } else {
+        UiUtils::ShowError(tr(MSG_THEATERS_ERROR));
+    }
+}
+
+void MainController::SetTheaterModel(QAbstractItemModel *model)
+{
+    delete _theater_proxy_model->sourceModel();
+    _theater_proxy_model->setSourceModel(model);
+    delete _theater_model;
+    _theater_model = (TheaterModel *) ((QSortFilterProxyModel *) model)->sourceModel();
+}
+
+void MainController::MoviesSearchStarted(int search_task_id)
+{
+    if (search_task_id != _current_movies_search_task_id) {
+        return;
+    }
+    SortMovies(true, SLOT(MoviesSortFinished(QAbstractItemModel*,int,bool)));
+}
+
+void MainController::MoviesSearchReply(int search_task_id, bool intermediate)
+{
+    if (search_task_id != _current_movies_search_task_id) {
+        return;
+    }
+    SortMovies(intermediate, SLOT(MoviesSortFinished(QAbstractItemModel*,int,bool)));
+}
+
+void MainController::MoviesSearchError(int search_task_id)
+{
+    if (search_task_id != _current_movies_search_task_id) {
+        return;
+    }
+    SortMovies(false, SLOT(MoviesSortErrorFinished(QAbstractItemModel*,int,bool)));
+}
+
+void MainController::MoviesSearchFinished(int search_task_id, bool success)
+{
+    Q_UNUSED(success);
+    if (search_task_id != _current_movies_search_task_id) {
+        return;
+    }
+    _main_window->SetBusy(false);
+}
+
+void MainController::SortMovies(bool intermediate, const char *slot)
+{
+    MovieModel *movie_model = new MovieModel(_cinema_schedule, this);
+    QSortFilterProxyModel *sort_model = new QSortFilterProxyModel(this);
+    sort_model->setSortCaseSensitivity(Qt::CaseInsensitive);
+    sort_model->setSortRole(MovieModel::SortRole);
+    sort_model->setDynamicSortFilter(false);
+    sort_model->setSourceModel(movie_model);
+    ItemModelSortClient *sort_client = new ItemModelSortClient(_sort_controller, this);
+    connect(sort_client, SIGNAL(SortFinished(QAbstractItemModel*,int,bool)), this, slot);
+    sort_client->Sort(sort_model, _current_movies_search_task_id, intermediate);
+    // proxy deletes itself
+}
+
+void MainController::MoviesSortFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
+{
+    if (search_task_id != _current_movies_search_task_id) {
+        return;
+    }
+    SetMovieModel(model);
+    if (!intermediate) {
+        AssertedWriteLocker locker(_cinema_schedule->GetLock());
+        _cinema_schedule->SetAllMoviesLoaded(true);
+        if (_movie_model->rowCount() == 0) {
+            _main_window->SetError(tr(MSG_NO_MOVIES_FOUND).arg(_settings->GetLocation().GetLocationName()));
+        }
+    }
+}
+
+void MainController::MoviesSortErrorFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
+{
+    Q_UNUSED(intermediate);
+    if (search_task_id != _current_movies_search_task_id) {
+        return;
+    }
+    SetMovieModel(model);
+    if (_movie_model->rowCount() == 0) {
+        _main_window->SetError(tr(MSG_MOVIES_ERROR));
+    } else {
+        UiUtils::ShowError(tr(MSG_MOVIES_ERROR));
+    }
+}
+
+void MainController::SetMovieModel(QAbstractItemModel *model)
+{
+    delete _movie_proxy_model->sourceModel();
+    _movie_proxy_model->setSourceModel(model);
+    delete _movie_model;
+    _movie_model = (MovieModel *) ((QSortFilterProxyModel *) model)->sourceModel();
+}
diff --git a/src/control/maincontroller.h b/src/control/maincontroller.h
new file mode 100644 (file)
index 0000000..30f9f4e
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef MAINCONTROLLER_H
+#define MAINCONTROLLER_H
+
+#include "data/location.h"
+#include "data/settings.h"
+
+#include <QObject>
+
+class MainWindow;
+class CinemaSchedule;
+class TheaterController;
+class MovieController;
+class LocationController;
+class ActionController;
+class ItemModelSortController;
+class TheaterModel;
+class MovieModel;
+class ConnectivityManager;
+class QAbstractItemModel;
+class QSortFilterProxyModel;
+
+class MainController : public QObject
+{
+    Q_OBJECT
+public:
+    MainController(MainWindow *main_window, Settings *settings, CinemaSchedule *cinema_schedule,
+                   TheaterController *theater_controller, MovieController *movie_controller,
+                   LocationController *location_controller, ActionController *action_controller,
+                   ItemModelSortController *sort_controller, QThread *search_worker);
+    ~MainController();
+
+public:
+    void Run();
+    void Search();
+    Q_SLOT void Search(Location location);
+
+private:
+    Q_SLOT void NetworkConnected();
+    Q_SLOT void NetworkDisconnected();
+    Q_SLOT void NetworkError();
+
+    Q_SLOT void SearchTheaters();
+    Q_SLOT void SearchMovies();
+    Q_SLOT void OpenAboutDialog();
+    void CancelTheaterSearch();
+    void CancelMovieSearch();
+
+    Q_SLOT void TheatersSearchStarted(int search_task_id);
+    Q_SLOT void TheatersSearchReply(int search_task_id, bool intermediate);
+    Q_SLOT void TheatersSearchError(int search_task_id);
+    Q_SLOT void TheatersSearchFinished(int search_task_id, bool success);
+
+    void SortTheaters(bool intermediate, const char *);
+    Q_SLOT void TheatersSortFinished(QAbstractItemModel *model, int search_task_id, bool intermediate);
+    Q_SLOT void TheatersSortErrorFinished(QAbstractItemModel *model, int search_task_id, bool intermediate);
+    void SetTheaterModel(QAbstractItemModel *model);
+
+    Q_SLOT void MoviesSearchStarted(int search_task_id);
+    Q_SLOT void MoviesSearchReply(int search_task_id, bool intermediate);
+    Q_SLOT void MoviesSearchError(int search_task_id);
+    Q_SLOT void MoviesSearchFinished(int search_task_id, bool success);
+
+    void SortMovies(bool intermediate, const char *);
+    Q_SLOT void MoviesSortFinished(QAbstractItemModel *model, int search_task_id, bool intermediate);
+    Q_SLOT void MoviesSortErrorFinished(QAbstractItemModel *model, int search_task_id, bool intermediate);
+    void SetMovieModel(QAbstractItemModel *model);
+
+private:
+    MainWindow *_main_window;
+    Settings *_settings;
+    CinemaSchedule *_cinema_schedule;
+    TheaterController *_theater_controller;
+    MovieController *_movie_controller;
+    LocationController *_location_controller;
+    ActionController *_action_controller;
+    ItemModelSortController *_sort_controller;
+    QThread *_search_worker;
+    ConnectivityManager *_connectivity_manager;
+    int _current_theater_search_task_id;
+    int _current_movies_search_task_id;
+    TheaterModel *_theater_model;
+    MovieModel *_movie_model;
+    QSortFilterProxyModel *_theater_proxy_model;
+    QSortFilterProxyModel *_movie_proxy_model;
+    Settings _last_search_settings;    
+};
+
+#endif // MAINCONTROLLER_H
diff --git a/src/control/moviecontroller.cpp b/src/control/moviecontroller.cpp
new file mode 100644 (file)
index 0000000..3b3b42b
--- /dev/null
@@ -0,0 +1,188 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "moviecontroller.h"
+
+#include "data/movie.h"
+#include "data/cinemaschedule.h"
+#include "control/actioncontroller.h"
+#include "control/itemmodelsortclient.h"
+#include "ui/moviewindow.h"
+#include "ui/movieschedulemodel.h"
+#include "ui/contextdialog.h"
+#include "ui/uiutils.h"
+#include "searchclients/movieschedulesearchclient.h"
+#include "utils/assertedlocker.h"
+#include "utils/asynccall.h"
+
+#include <QSortFilterProxyModel>
+#include <iostream>
+
+static const char *MSG_NO_MOVIE_SCHEDULE_FOUND = QT_TRANSLATE_NOOP("MovieController", "No schedule found for %1.");
+static const char *MSG_MOVIE_SCHEDULE_ERROR = QT_TRANSLATE_NOOP("MovieController", "Error on fetching movie schedule.");
+
+MovieController::MovieController(MovieWindow *movie_window, CinemaSchedule *cinema_schedule,
+                                 ActionController *action_controller, ItemModelSortController *sort_controller,
+                                 QThread *search_worker)
+                                     : QObject(0),
+                                     _movie_window(movie_window),
+                                     _cinema_schedule(cinema_schedule),
+                                     _action_controller(action_controller),
+                                     _sort_controller(sort_controller),
+                                     _search_worker(search_worker),
+                                     _current_search_task_id(MovieScheduleSearchClient::INVALID_SEARCH_TASK_ID),
+                                     _movie_schedule_model(0),
+                                     _movie_schedule_proxy_model(new QSortFilterProxyModel(this))
+{
+    connect(_movie_window, SIGNAL(ScheduleEntrySelected(ScheduleEntryKey)), this, SLOT(ScheduleEntrySelected(ScheduleEntryKey)));
+}
+
+void MovieController::ShowMovie(MovieKey movie_key)
+{
+    CancelSearch();
+    AssertedReadLocker locker(_cinema_schedule->GetLock());
+    _movie_key = movie_key;
+    const Movie *movie = ((const CinemaSchedule *) _cinema_schedule)->FindMovie(movie_key);
+    if (movie != 0) {
+        SetModel(0);
+        _movie_window->SetMovieName(movie->GetName());
+        _movie_window->SetMovieScheduleModel(_movie_schedule_proxy_model);
+        _movie_window->show();
+        MovieScheduleSearchClient *client = new MovieScheduleSearchClient(_cinema_schedule);
+        _current_search_task_id = client->GetSearchTaskId();
+        connect(client, SIGNAL(SearchStarted(int)), this, SLOT(SearchStarted(int)));
+        connect(client, SIGNAL(Reply(int, bool)), this, SLOT(Reply(int, bool)));
+        connect(client, SIGNAL(SearchFinished(int, bool)), this, SLOT(SearchFinished(int, bool)));
+        connect(client, SIGNAL(Error(int)), this, SLOT(Error(int)));
+        client->moveToThread(_search_worker);
+        CallAsync(client, &MovieScheduleSearchClient::SearchSchedule, movie->GetKey(), movie->GetTheatersUrl());
+        // search client deletes itself
+    }
+}
+
+void MovieController::Cancel()
+{
+    _movie_window->hide();
+    CancelSearch();
+}
+
+void MovieController::CancelSearch()
+{
+    SetModel(0);
+    AssertedWriteLocker locker(_cinema_schedule->GetLock());
+    _current_search_task_id = MovieScheduleSearchClient::INVALID_SEARCH_TASK_ID;
+    MovieScheduleSearchClient::CancelAllRunningSearchs();
+}
+
+void MovieController::ScheduleEntrySelected(ScheduleEntryKey schedule_entry_key)
+{
+    ContextDialog *dialog = new ContextDialog(_cinema_schedule, _movie_window);
+    connect(dialog, SIGNAL(AddToCalendar(ScheduleEntryKey)), _action_controller, SLOT(AddToCalendar(ScheduleEntryKey)));
+    connect(dialog, SIGNAL(CallTheaterByPhone(CinemaKey)), _action_controller, SLOT(CallTheaterByPhone(CinemaKey)));
+    connect(dialog, SIGNAL(FindRouteToTheater(CinemaKey)), _action_controller, SLOT(FindRouteToTheater(CinemaKey)));
+    connect(dialog, SIGNAL(SearchMovieInWeb(MovieKey)), _action_controller, SLOT(SearchMovieInWeb(MovieKey)));
+    connect(dialog, SIGNAL(SearchTheaterInWeb(CinemaKey)), _action_controller, SLOT(SearchTheaterInWeb(CinemaKey)));
+    dialog->Show(schedule_entry_key);
+    // dialog deletes itself
+}
+
+void MovieController::SearchStarted(int search_task_id)
+{
+    if (search_task_id != _current_search_task_id) {
+        return;
+    }
+    _movie_window->SetBusy(true);
+}
+
+void MovieController::Reply(int search_task_id, bool intermediate)
+{
+    if (search_task_id != _current_search_task_id) {
+        return;
+    }
+    Sort(intermediate, SLOT(SortFinished(QAbstractItemModel*,int,bool)));
+}
+
+void MovieController::Error(int search_task_id)
+{
+    if (search_task_id != _current_search_task_id) {
+        return;
+    }
+    Sort(false, SLOT(SortErrorFinished(QAbstractItemModel*,int,bool)));
+}
+
+void MovieController::SearchFinished(int search_task_id, bool success)
+{
+    Q_UNUSED(success);
+    if (search_task_id != _current_search_task_id) {
+        return;
+    }
+    _movie_window->SetBusy(false);
+}
+
+void MovieController::Sort(bool intermediate, const char *slot)
+{
+    MovieScheduleModel *movie_schedule_model = new MovieScheduleModel(_cinema_schedule, _movie_key, this);
+    movie_schedule_model->Update();
+    QSortFilterProxyModel *sort_model = new QSortFilterProxyModel(this);
+    sort_model->setSortCaseSensitivity(Qt::CaseInsensitive);
+    sort_model->setSortRole(MovieScheduleModel::SortRole);
+    sort_model->setDynamicSortFilter(false);
+    sort_model->setSourceModel(movie_schedule_model);
+    ItemModelSortClient *sort_client = new ItemModelSortClient(_sort_controller, this);
+    connect(sort_client, SIGNAL(SortFinished(QAbstractItemModel*,int,bool)), this, slot);
+    sort_client->Sort(sort_model, _current_search_task_id, intermediate);
+    // proxy deletes itself
+}
+
+void MovieController::SortFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
+{
+    if (search_task_id != _current_search_task_id) {
+        return;
+    }
+    SetModel(model);
+    if (!intermediate) {
+        if (_movie_schedule_model->rowCount() == 0) {
+            _movie_window->SetError(tr(MSG_NO_MOVIE_SCHEDULE_FOUND).arg(_movie_key.GetName()));
+        }
+    }
+}
+
+void MovieController::SortErrorFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
+{
+    Q_UNUSED(intermediate);
+    if (search_task_id != _current_search_task_id) {
+        return;
+    }
+    SetModel(model);
+    if (_movie_schedule_model->rowCount() == 0) {
+        _movie_window->SetError(tr(MSG_MOVIE_SCHEDULE_ERROR));
+    } else {
+        UiUtils::ShowError(tr(MSG_MOVIE_SCHEDULE_ERROR));
+    }
+}
+
+void MovieController::SetModel(QAbstractItemModel *model)
+{
+    delete _movie_schedule_proxy_model->sourceModel();
+    _movie_schedule_proxy_model->setSourceModel(model);
+    delete _movie_schedule_model;
+    if (model != 0) {
+        _movie_schedule_model = (MovieScheduleModel *) ((QSortFilterProxyModel *) model)->sourceModel();
+    } else {
+        _movie_schedule_model = 0;
+    }
+}
diff --git a/src/control/moviecontroller.h b/src/control/moviecontroller.h
new file mode 100644 (file)
index 0000000..dab70b0
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef MOVIECONTROLLER_H
+#define MOVIECONTROLLER_H
+
+#include "data/scheduleentrykey.h"
+#include "data/moviekey.h"
+
+#include <QObject>
+
+class MovieWindow;
+class CinemaSchedule;
+class ActionController;
+class ItemModelSortController;
+class MovieScheduleModel;
+class QAbstractItemModel;
+class QSortFilterProxyModel;
+
+class MovieController : public QObject
+{
+    Q_OBJECT
+public:
+    MovieController(MovieWindow *movie_window, CinemaSchedule *cinema_schedule, ActionController *action_controller,
+                    ItemModelSortController *sort_controller, QThread *search_worker);
+
+public:
+    Q_SLOT void ShowMovie(MovieKey movie_key);
+    void Cancel();
+
+private:
+    void CancelSearch();
+    Q_SLOT void ScheduleEntrySelected(ScheduleEntryKey schedule_entry_key);
+    Q_SLOT void SearchStarted(int search_task_id);
+    Q_SLOT void Reply(int search_task_id, bool intermediate);
+    Q_SLOT void Error(int search_task_id);
+    Q_SLOT void SearchFinished(int search_task_id, bool success);
+
+    void Sort(bool intermediate, const char *);
+    Q_SLOT void SortFinished(QAbstractItemModel *model, int search_task_id, bool intermediate);
+    Q_SLOT void SortErrorFinished(QAbstractItemModel *model, int search_task_id, bool intermediate);
+    void SetModel(QAbstractItemModel *model);
+
+private:
+    MovieWindow *_movie_window;
+    CinemaSchedule *_cinema_schedule;
+    ActionController *_action_controller;
+    ItemModelSortController *_sort_controller;
+    QThread *_search_worker;
+    int _current_search_task_id;
+    MovieScheduleModel *_movie_schedule_model;
+    QSortFilterProxyModel *_movie_schedule_proxy_model;
+    MovieKey _movie_key;
+};
+
+#endif // MOVIECONTROLLER_H
diff --git a/src/control/settingscontroller.cpp b/src/control/settingscontroller.cpp
new file mode 100644 (file)
index 0000000..a5e1188
--- /dev/null
@@ -0,0 +1,168 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "settingscontroller.h"
+
+#include "data/settings.h"
+
+#include <QFile>
+#include <QXmlStreamReader>
+#include <QXmlStreamWriter>
+#include <QDir>
+#include <iostream>
+
+SettingsController::SettingsController(Settings *settings)
+    : _settings(settings)
+{
+}
+
+enum State {
+    STATE_DOCUMENT,
+    STATE_SETTINGS,
+    STATE_LOCATION,
+    STATE_LOCATION_NAME,
+    STATE_PREVIOUS_LOCATIONS,
+    STATE_PREVIOUS_LOCATION,
+    STATE_PREVIOUS_LOCATION_NAME,
+    STATE_GPS,
+    STATE_SEARCH,
+};
+
+void SettingsController::Load()
+{
+    QFile file(GetSettingsFileName());
+    if (file.open(QIODevice::ReadOnly)) {
+        QXmlStreamReader xml(&file);
+        State state = STATE_DOCUMENT;
+        Location location;
+        Settings::Locations previous_locations;
+        Location previous_location;
+        while (!xml.atEnd()) {
+            QXmlStreamReader::TokenType token = xml.readNext();
+            if (token == QXmlStreamReader::StartElement) {
+                if (state == STATE_DOCUMENT && xml.name() == "settings") {
+                    state = STATE_SETTINGS;
+                } else if (state == STATE_SETTINGS && xml.name() == "location") {
+                    state = STATE_LOCATION;
+                } else if (state == STATE_LOCATION && xml.name() == "name") {
+                    state = STATE_LOCATION_NAME;
+                } else if (state == STATE_SETTINGS && xml.name() == "previous-locations") {
+                    state = STATE_PREVIOUS_LOCATIONS;
+                } else if (state == STATE_PREVIOUS_LOCATIONS && xml.name() == "location") {
+                    state = STATE_PREVIOUS_LOCATION;
+                } else if (state == STATE_PREVIOUS_LOCATION && xml.name() == "name") {
+                    state = STATE_PREVIOUS_LOCATION_NAME;
+                } else if (state == STATE_SETTINGS && xml.name() == "gps") {
+                    QString enabled = xml.attributes().value("enabled").toString();
+                    _settings->SetGPSEnabled(enabled == "yes");
+                    state = STATE_GPS;
+                } else if (state == STATE_SETTINGS && xml.name() == "search") {
+                    state = STATE_SEARCH;
+                } else {
+                    state = STATE_DOCUMENT;
+                }
+            } else if (token == QXmlStreamReader::EndElement) {
+                if (state == STATE_SEARCH) {
+                    state = STATE_SETTINGS;
+                } else if (state == STATE_GPS) {
+                    state = STATE_SETTINGS;
+                } else if (state == STATE_PREVIOUS_LOCATION_NAME) {
+                    state = STATE_PREVIOUS_LOCATION;
+                } else if (state == STATE_PREVIOUS_LOCATION) {
+                    if (previous_location.IsValid()) {
+                        previous_locations.append(previous_location);
+                    }
+                    state = STATE_PREVIOUS_LOCATIONS;
+                } else if (state == STATE_PREVIOUS_LOCATIONS) {
+                    state = STATE_SETTINGS;
+                } else if (state == STATE_LOCATION_NAME) {
+                    state = STATE_LOCATION;
+                } else if (state == STATE_LOCATION) {
+                    state = STATE_SETTINGS;
+                } else if (state == STATE_SETTINGS) {
+                    state = STATE_DOCUMENT;
+                }
+            } else if (token == QXmlStreamReader::Characters) {
+                if (state == STATE_LOCATION_NAME) {
+                    location.SetLocationName(xml.text().toString());
+                } else if (state == STATE_PREVIOUS_LOCATION_NAME) {
+                    previous_location.SetLocationName(xml.text().toString());
+                } else if (state == STATE_SEARCH) {
+                    if (xml.text() == "theaters") {
+                        _settings->SetSearchObjectsType(Settings::THEATERS);
+                    } else if (xml.text() == "movies") {
+                        _settings->SetSearchObjectsType(Settings::MOVIES);
+                    }
+                }
+            }
+        }
+        if (xml.hasError()) {
+            // TODO error message unable to read setting files?
+            file.close();
+            QDir().remove(GetSettingsFileName());
+        } else {
+            _settings->SetLocation(location);
+            _settings->SetPreviousLocations(previous_locations);
+        }
+    }
+}
+
+void SettingsController::Save()
+{
+    QFile file(GetSettingsFileName());
+    if (file.open(QIODevice::WriteOnly)) {
+        QXmlStreamWriter xml(&file);
+        xml.setAutoFormatting(true);
+        xml.writeStartDocument();
+        xml.writeStartElement("settings");
+        xml.writeStartElement("location");
+        xml.writeTextElement("name", _settings->GetLocation().GetLocationName());
+        xml.writeEndElement();
+        xml.writeStartElement("previous-locations");
+        Q_FOREACH(Location location, _settings->GetPreviousLocations()) {
+            xml.writeStartElement("location");
+            xml.writeTextElement("name", location.GetLocationName());
+            xml.writeEndElement();
+        }
+        xml.writeEndElement();
+        QString v;
+        xml.writeStartElement("gps");
+        xml.writeAttribute("enabled", _settings->IsGPSEnabled() ? "yes" : "no");
+        xml.writeEndElement();
+        switch (_settings->GetSearchObjectsType()) {
+        case Settings::THEATERS:
+            v = "theaters";
+            break;
+        case Settings::MOVIES:
+            v = "movies";
+            break;
+        }
+        xml.writeTextElement("search", v);
+        xml.writeEndElement();
+        xml.writeEndDocument();
+    } else {
+        // TODO error message unable to create file
+        std::cout << "Failed to open file " << qPrintable(GetSettingsFileName()) << std::endl;
+    }
+}
+
+QString SettingsController::GetSettingsFileName()
+{
+    QString dirpath = QDir::homePath() + "/.movie-schedule";
+    QDir().mkpath(dirpath);
+    return dirpath + "/settings.xml";
+}
diff --git a/src/control/settingscontroller.h b/src/control/settingscontroller.h
new file mode 100644 (file)
index 0000000..7d7889c
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef SETTINGSCONTROLLER_H
+#define SETTINGSCONTROLLER_H
+
+#include <QString>
+
+class Settings;
+
+class SettingsController
+{
+public:
+    SettingsController(Settings *settings);
+
+    void Load();
+    void Save();
+
+private:
+    QString GetSettingsFileName();
+
+private:
+    Settings *_settings;
+};
+
+#endif // SETTINGSCONTROLLER_H
diff --git a/src/control/theatercontroller.cpp b/src/control/theatercontroller.cpp
new file mode 100644 (file)
index 0000000..21d8db8
--- /dev/null
@@ -0,0 +1,187 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "theatercontroller.h"
+
+#include "data/cinema.h"
+#include "data/cinemaschedule.h"
+#include "control/actioncontroller.h"
+#include "control/itemmodelsortclient.h"
+#include "ui/theaterwindow.h"
+#include "ui/theaterschedulemodel.h"
+#include "ui/contextdialog.h"
+#include "ui/uiutils.h"
+#include "searchclients/theaterschedulesearchclient.h"
+#include "utils/assertedlocker.h"
+#include "utils/asynccall.h"
+
+#include <QSortFilterProxyModel>
+#include <iostream>
+
+static const char *MSG_NO_THEATER_SCHEDULE_FOUND = QT_TRANSLATE_NOOP("TheaterController", "No schedule found for %1.");
+static const char *MSG_THEATER_SCHEDULE_ERROR = QT_TRANSLATE_NOOP("TheaterController", "Error on fetching theater schedule.");
+
+TheaterController::TheaterController(TheaterWindow *theater_window, CinemaSchedule *cinema_schedule, ActionController *action_controller,
+                                     ItemModelSortController *sort_controller, QThread *search_worker)
+                                         : QObject(0),
+                                         _theater_window(theater_window),
+                                         _cinema_schedule(cinema_schedule),
+                                         _action_controller(action_controller),
+                                         _sort_controller(sort_controller),
+                                         _search_worker(search_worker),
+                                         _current_search_task_id(TheaterScheduleSearchClient::INVALID_SEARCH_TASK_ID),
+                                         _theater_schedule_model(0),
+                                         _theater_schedule_proxy_model(new QSortFilterProxyModel(this))
+{
+    connect(_theater_window, SIGNAL(ScheduleEntrySelected(ScheduleEntryKey)), this, SLOT(ScheduleEntrySelected(ScheduleEntryKey)));
+}
+
+void TheaterController::ShowTheater(CinemaKey cinema_key)
+{
+    CancelSearch();
+    AssertedReadLocker locker(_cinema_schedule->GetLock());
+    _cinema_key = cinema_key;
+    const Cinema *cinema = ((const CinemaSchedule *) _cinema_schedule)->FindCinema(cinema_key);
+    if (cinema != 0) {
+        SetModel(0);
+        _theater_window->SetTheaterName(cinema->GetName());
+        _theater_window->SetTheaterScheduleModel(_theater_schedule_proxy_model);
+        _theater_window->show();
+        TheaterScheduleSearchClient *client = new TheaterScheduleSearchClient(_cinema_schedule);
+        _current_search_task_id = client->GetSearchTaskId();
+        connect(client, SIGNAL(SearchStarted(int)), this, SLOT(SearchStarted(int)));
+        connect(client, SIGNAL(Reply(int,bool)), this, SLOT(Reply(int,bool)));
+        connect(client, SIGNAL(SearchFinished(int,bool)), this, SLOT(SearchFinished(int,bool)));
+        connect(client, SIGNAL(Error(int)), this, SLOT(Error(int)));
+        client->moveToThread(_search_worker);
+        CallAsync(client, &TheaterScheduleSearchClient::SearchSchedule, cinema->GetKey(), cinema->GetMoviesUrl());
+        // client deletes itself
+    }
+}
+
+void TheaterController::Cancel()
+{
+    _theater_window->hide();
+    CancelSearch();
+}
+
+void TheaterController::CancelSearch()
+{
+    SetModel(0);
+    AssertedWriteLocker locker(_cinema_schedule->GetLock());
+    _current_search_task_id = TheaterScheduleSearchClient::INVALID_SEARCH_TASK_ID;
+    TheaterScheduleSearchClient::CancelAllRunningSearchs();
+}
+
+void TheaterController::ScheduleEntrySelected(ScheduleEntryKey schedule_entry_key)
+{
+    ContextDialog *dialog = new ContextDialog(_cinema_schedule, _theater_window);
+    connect(dialog, SIGNAL(AddToCalendar(ScheduleEntryKey)), _action_controller, SLOT(AddToCalendar(ScheduleEntryKey)));
+    connect(dialog, SIGNAL(CallTheaterByPhone(CinemaKey)), _action_controller, SLOT(CallTheaterByPhone(CinemaKey)));
+    connect(dialog, SIGNAL(FindRouteToTheater(CinemaKey)), _action_controller, SLOT(FindRouteToTheater(CinemaKey)));
+    connect(dialog, SIGNAL(SearchMovieInWeb(MovieKey)), _action_controller, SLOT(SearchMovieInWeb(MovieKey)));
+    connect(dialog, SIGNAL(SearchTheaterInWeb(CinemaKey)), _action_controller, SLOT(SearchTheaterInWeb(CinemaKey)));
+    dialog->Show(schedule_entry_key);
+    // dialog deletes itself
+}
+
+void TheaterController::SearchStarted(int search_task_id)
+{
+    if (search_task_id != _current_search_task_id) {
+        return;
+    }
+    _theater_window->SetBusy(true);
+}
+
+void TheaterController::Reply(int search_task_id, bool intermediate)
+{
+    if (search_task_id != _current_search_task_id) {
+        return;
+    }
+    Sort(intermediate, SLOT(SortFinished(QAbstractItemModel*,int,bool)));
+}
+
+void TheaterController::Error(int search_task_id)
+{
+    if (search_task_id != _current_search_task_id) {
+        return;
+    }
+    Sort(false, SLOT(SortErrorFinished(QAbstractItemModel*,int,bool)));
+}
+
+void TheaterController::SearchFinished(int search_task_id, bool success)
+{
+    Q_UNUSED(success);
+    if (search_task_id != _current_search_task_id) {
+        return;
+    }
+    _theater_window->SetBusy(false);
+}
+
+void TheaterController::Sort(bool intermediate, const char *slot)
+{
+    TheaterScheduleModel *theater_schedule_model = new TheaterScheduleModel(_cinema_schedule, _cinema_key, this);
+    theater_schedule_model->Update();
+    QSortFilterProxyModel *sort_model = new QSortFilterProxyModel(this);
+    sort_model->setSortCaseSensitivity(Qt::CaseInsensitive);
+    sort_model->setSortRole(TheaterScheduleModel::SortRole);
+    sort_model->setDynamicSortFilter(false);
+    sort_model->setSourceModel(theater_schedule_model);
+    ItemModelSortClient *sort_client = new ItemModelSortClient(_sort_controller, this);
+    connect(sort_client, SIGNAL(SortFinished(QAbstractItemModel*,int,bool)), this, slot);
+    sort_client->Sort(sort_model, _current_search_task_id, intermediate);
+    // proxy deletes itself
+}
+
+void TheaterController::SortFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
+{
+    if (search_task_id != _current_search_task_id) {
+        return;
+    }
+    SetModel(model);
+    if (!intermediate) {
+        if (_theater_schedule_model->rowCount() == 0) {
+            _theater_window->SetError(tr(MSG_NO_THEATER_SCHEDULE_FOUND).arg(_cinema_key.GetName()));
+        }
+    }
+}
+
+void TheaterController::SortErrorFinished(QAbstractItemModel *model, int search_task_id, bool intermediate)
+{
+    Q_UNUSED(intermediate);
+    if (search_task_id != _current_search_task_id) {
+        return;
+    }
+    SetModel(model);
+    if (_theater_schedule_model->rowCount() == 0) {
+        _theater_window->SetError(tr(MSG_THEATER_SCHEDULE_ERROR));
+    } else {
+        UiUtils::ShowError(tr(MSG_THEATER_SCHEDULE_ERROR));
+    }
+}
+
+void TheaterController::SetModel(QAbstractItemModel *model)
+{
+    delete _theater_schedule_proxy_model->sourceModel();
+    _theater_schedule_proxy_model->setSourceModel(model);
+    delete _theater_schedule_model;
+    if (model != 0) {
+        _theater_schedule_model = (TheaterScheduleModel *) ((QSortFilterProxyModel *) model)->sourceModel();
+    } else {
+        _theater_schedule_model = 0;
+    }
+}
diff --git a/src/control/theatercontroller.h b/src/control/theatercontroller.h
new file mode 100644 (file)
index 0000000..a74a29d
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef THEATERCONTROLLER_H
+#define THEATERCONTROLLER_H
+
+#include "data/scheduleentrykey.h"
+#include "data/cinemakey.h"
+
+#include <QObject>
+
+class TheaterWindow;
+class CinemaSchedule;
+class TheaterScheduleModel;
+class ItemModelSortController;
+class ScheduleEntry;
+class ActionController;
+class QAbstractItemModel;
+class QSortFilterProxyModel;
+
+class TheaterController : public QObject
+{
+    Q_OBJECT
+public:
+    TheaterController(TheaterWindow *theater_window, CinemaSchedule *cinema_schedule, ActionController *action_controller,
+                      ItemModelSortController *sort_controller, QThread *search_worker);
+
+public:
+    Q_SLOT void ShowTheater(CinemaKey cinema_key);
+    void Cancel();
+
+private:
+    void CancelSearch();
+    Q_SLOT void ScheduleEntrySelected(ScheduleEntryKey schedule_entry_key);
+    Q_SLOT void SearchStarted(int search_task_id);
+    Q_SLOT void Reply(int search_task_id, bool intermediate);
+    Q_SLOT void Error(int search_task_id);
+    Q_SLOT void SearchFinished(int search_task_id, bool success);
+
+    void Sort(bool intermediate, const char *);
+    Q_SLOT void SortFinished(QAbstractItemModel *model, int search_task_id, bool intermediate);
+    Q_SLOT void SortErrorFinished(QAbstractItemModel *model, int search_task_id, bool intermediate);
+    void SetModel(QAbstractItemModel *model);
+
+private:
+    TheaterWindow *_theater_window;
+    CinemaSchedule *_cinema_schedule;
+    ActionController *_action_controller;
+    ItemModelSortController *_sort_controller;
+    QThread *_search_worker;
+    int _current_search_task_id;
+    TheaterScheduleModel *_theater_schedule_model;
+    QSortFilterProxyModel *_theater_schedule_proxy_model;
+    CinemaKey _cinema_key;
+};
+
+#endif // THEATERCONTROLLER_H
diff --git a/src/data/cinema.cpp b/src/data/cinema.cpp
new file mode 100644 (file)
index 0000000..447e201
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "cinema.h"
+
+Cinema::Cinema()
+{
+}
diff --git a/src/data/cinema.h b/src/data/cinema.h
new file mode 100644 (file)
index 0000000..89234b9
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef CINEMA_H
+#define CINEMA_H
+
+#include "cinemakey.h"
+
+#include <QString>
+
+class Cinema
+{
+public:
+    Cinema();
+
+    CinemaKey GetKey() const { return CinemaKey(_name, _address); }
+
+    bool IsValid() const { return !_name.isEmpty(); }
+
+    QString GetName() const { return _name; }
+    void SetName(const QString &name) { _name = name; }
+
+    QString GetAddress() const { return _address; }
+    void SetAddress(const QString &address) { _address = address; }
+
+    QString GetMoviesUrl() const { return _movies_url; }
+    void SetMoviesUrl(const QString &movies_url) { _movies_url = movies_url; }
+
+    QString GetTelephone() const { return _telephone; }
+    void SetTelephone(const QString &telephone) { _telephone = telephone; }
+
+private:
+    QString _name;
+    QString _address;
+    QString _movies_url;
+    QString _telephone;
+};
+
+#endif // CINEMA_H
diff --git a/src/data/cinemakey.cpp b/src/data/cinemakey.cpp
new file mode 100644 (file)
index 0000000..10ef1f7
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "cinemakey.h"
+
+#include <qhash.h>
+
+CinemaKey::CinemaKey(const QString &name, const QString &address)
+    : _name(name),
+    _address(address)
+{
+}
+
+bool operator==(const CinemaKey &lhs, const CinemaKey &rhs)
+{
+    return lhs.GetName() == rhs.GetName()
+            && lhs.GetAddress() == rhs.GetAddress();
+}
+
+uint qHash(const CinemaKey &key)
+{
+    return qHash(key.GetName()) + qHash(key.GetAddress());
+}
diff --git a/src/data/cinemakey.h b/src/data/cinemakey.h
new file mode 100644 (file)
index 0000000..25ea70d
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef CINEMAKEY_H
+#define CINEMAKEY_H
+
+#include <QString>
+#include <QMetaType>
+
+class CinemaKey
+{
+public:
+    CinemaKey() {}
+    CinemaKey(const QString &name, const QString &address);
+
+    QString GetName() const { return _name; }
+    void SetName(const QString &name) { _name = name; }
+
+    QString GetAddress() const { return _address; }
+    void SetAddress(const QString &address) { _address = address; }
+
+private:
+    QString _name;
+    QString _address;
+};
+
+bool operator==(const CinemaKey &lhs, const CinemaKey &rhs);
+
+uint qHash(const CinemaKey &);
+
+Q_DECLARE_METATYPE(CinemaKey);
+
+#endif // CINEMAKEY_H
diff --git a/src/data/cinemaschedule.cpp b/src/data/cinemaschedule.cpp
new file mode 100644 (file)
index 0000000..76e78a9
--- /dev/null
@@ -0,0 +1,227 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "cinemaschedule.h"
+
+#include "cinema.h"
+#include "movie.h"
+
+CinemaSchedule::CinemaSchedule()
+    : _lock(),
+    _all_cinemas_loaded(false),
+    _all_movies_loaded(false)
+{
+}
+
+void CinemaSchedule::Clear()
+{
+    _lock.AssertLockedForWrite();
+    _schedules.clear();
+    foreach (Movie *movie, _movies.values()) {
+        delete movie;
+    }
+    _movies.clear();
+    _all_movies_loaded = false;
+    foreach (Cinema *cinema, _cinemas.values()) {
+        delete cinema;
+    }
+    _cinemas.clear();
+    _all_cinemas_loaded = false;
+}
+
+Cinema *CinemaSchedule::FindCinema(const CinemaKey &key)
+{
+    _lock.AssertLockedForWrite();
+    if (!_cinemas.contains(key)) {
+        return 0;
+    }
+    return _cinemas[key];
+}
+
+const Cinema *CinemaSchedule::FindCinema(const CinemaKey &key) const
+{
+    _lock.AssertLockedForRead();
+    if (!_cinemas.contains(key)) {
+        return 0;
+    }
+    return _cinemas[key];
+}
+
+Cinema *CinemaSchedule::AddCinema(const CinemaKey &key)
+{
+    _lock.AssertLockedForWrite();
+    Cinema *cinema = 0;
+    if (_cinemas.contains(key))
+    {
+        cinema = _cinemas[key];
+        if (cinema != 0) {
+            return cinema;
+        }
+    }
+    cinema = new Cinema();
+    cinema->SetName(key.GetName());
+    cinema->SetAddress(key.GetAddress());
+    _cinemas[key] = cinema;
+    return cinema;
+}
+
+Movie *CinemaSchedule::FindMovie(const MovieKey &key)
+{
+    _lock.AssertLockedForWrite();
+    if (!_movies.contains(key)) {
+        return 0;
+    }
+    return _movies[key];
+}
+
+const Movie *CinemaSchedule::FindMovie(const MovieKey &key) const
+{
+    _lock.AssertLockedForRead();
+    if (!_movies.contains(key)) {
+        return 0;
+    }
+    return _movies[key];
+}
+
+Movie *CinemaSchedule::AddMovie(const MovieKey &key)
+{
+    _lock.AssertLockedForWrite();
+    Movie *movie = 0;
+    if (_movies.contains(key)){
+        movie = _movies[key];
+        if (movie != 0) {
+            return movie;
+        }
+    }
+    movie = new Movie();
+    movie->SetName(key.GetName());
+    _movies[key] = movie;
+    return movie;
+}
+
+const CinemaSchedule::ScheduleDates CinemaSchedule::GetScheduleDates() const
+{
+    _lock.AssertLockedForRead();
+    ScheduleDates result;
+    Q_FOREACH(const ScheduleEntry &entry, _schedules) {
+        result |= entry.GetDate();
+    }
+    return result;
+}
+
+const CinemaSchedule::ScheduleDates CinemaSchedule::GetScheduleDates(const Cinema *cinema) const
+{
+    _lock.AssertLockedForRead();
+    ScheduleDates result;
+    Q_FOREACH(const ScheduleEntry &entry, _schedules) {
+        if (entry.GetCinema() == cinema) {
+            result |= entry.GetDate();
+        }
+    }
+    return result;
+}
+
+const CinemaSchedule::ScheduleDates CinemaSchedule::GetScheduleDates(const Movie *movie) const
+{
+    _lock.AssertLockedForRead();
+    ScheduleDates result;
+    Q_FOREACH(const ScheduleEntry &entry, _schedules) {
+        if (entry.GetMovie() == movie) {
+            result |= entry.GetDate();
+        }
+    }
+    return result;
+}
+
+ScheduleEntry CinemaSchedule::FindScheduleEntry(const ScheduleEntryKey &schedule_entry_key) const
+{
+    _lock.AssertLockedForRead();
+    const Cinema *cinema = FindCinema(schedule_entry_key.GetCinemaKey());
+    const Movie *movie = FindMovie(schedule_entry_key.GetMovieKey());
+    ScheduleEntry schedule_entry;
+    if (cinema != 0 && movie != 0) {
+        Q_FOREACH(const ScheduleEntry &entry, _schedules) {
+            if (entry.GetCinema() == cinema && entry.GetMovie() == movie
+                && entry.GetStartTime() == schedule_entry_key.GetStartTime()
+                && entry.GetDate() == schedule_entry_key.GetDate()) {
+                schedule_entry = entry;
+                break;
+            }
+        }
+    }
+    return schedule_entry;
+}
+
+const CinemaSchedule::Schedules CinemaSchedule::GetSchedules(const Cinema *cinema) const
+{
+    _lock.AssertLockedForRead();
+    Schedules result;
+    Q_FOREACH(const ScheduleEntry &entry, _schedules) {
+        if (entry.GetCinema() == cinema) {
+            result |= entry;
+        }
+    }
+    return result;
+}
+
+const CinemaSchedule::Schedules CinemaSchedule::GetSchedules(const Movie *movie) const
+{
+    _lock.AssertLockedForRead();
+    Schedules result;
+    Q_FOREACH(const ScheduleEntry &entry, _schedules) {
+        if (entry.GetMovie() == movie) {
+            result |= entry;
+        }
+    }
+    return result;
+}
+
+const CinemaSchedule::ScheduleKeys CinemaSchedule::GetScheduleKeys(const CinemaKey &cinema_key) const
+{
+    _lock.AssertLockedForRead();
+    ScheduleKeys result;
+    const Cinema *cinema = FindCinema(cinema_key);
+    if (cinema != 0) {
+        Q_FOREACH(const ScheduleEntry &entry, _schedules) {
+            if (entry.GetCinema() == cinema) {
+                result |= entry.GetKey();
+            }
+        }
+    }
+    return result;
+}
+
+const CinemaSchedule::ScheduleKeys CinemaSchedule::GetScheduleKeys(const MovieKey &movie_key) const
+{
+    _lock.AssertLockedForRead();
+    ScheduleKeys result;
+    const Movie *movie = FindMovie(movie_key);
+    if (movie != 0) {
+        Q_FOREACH(const ScheduleEntry &entry, _schedules) {
+            if (entry.GetMovie() == movie) {
+                result |= entry.GetKey();
+            }
+        }
+    }
+    return result;
+}
+
+void CinemaSchedule::AddSchedule(const Cinema *cinema, const Movie *movie, const QTime &start_time, const QDate &date)
+{
+    _lock.AssertLockedForWrite();
+    _schedules |= ScheduleEntry(cinema, movie, start_time, date);
+}
diff --git a/src/data/cinemaschedule.h b/src/data/cinemaschedule.h
new file mode 100644 (file)
index 0000000..3a0fd9f
--- /dev/null
@@ -0,0 +1,87 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef CINEMASCHEDULE_H
+#define CINEMASCHEDULE_H
+
+#include "location.h"
+#include "cinemakey.h"
+#include "moviekey.h"
+#include "scheduleentrykey.h"
+#include "scheduleentry.h"
+#include "utils/assertedlock.h"
+
+#include <QHash>
+#include <QSet>
+#include <QReadWriteLock>
+
+class Cinema;
+class Movie;
+
+class CinemaSchedule
+{
+    Q_DISABLE_COPY(CinemaSchedule);
+public:
+    typedef QHash<CinemaKey, Cinema *> Cinemas;
+    typedef QHash<MovieKey, Movie *> Movies;
+    typedef QSet<QDate> ScheduleDates;
+    typedef QSet<ScheduleEntry> Schedules;
+    typedef QSet<ScheduleEntryKey> ScheduleKeys;
+public:
+    CinemaSchedule();
+
+    AssertedLock *GetLock() const { return const_cast<AssertedLock *>(&_lock); }
+
+    void Clear();
+
+    bool AreAllCinemasLoaded() const { _lock.AssertLockedForRead(); return _all_cinemas_loaded; }
+    void SetAllCinemasLoaded(bool all_cinemas_loaded) { _lock.AssertLockedForWrite(); _all_cinemas_loaded = all_cinemas_loaded; }
+    const Cinemas GetCinemas() const { _lock.AssertLockedForRead(); return _cinemas; }
+    Cinema *FindCinema(const CinemaKey &);
+    const Cinema *FindCinema(const CinemaKey &) const;
+    Cinema *AddCinema(const CinemaKey &);
+
+    bool AreAllMoviesLoaded() const { _lock.AssertLockedForRead(); return _all_movies_loaded; }
+    void SetAllMoviesLoaded(bool all_movies_loaded) { _lock.AssertLockedForWrite(); _all_movies_loaded = all_movies_loaded; }
+    const Movies GetMovies() const { _lock.AssertLockedForRead(); return _movies; }
+    Movie *FindMovie(const MovieKey &);
+    const Movie *FindMovie(const MovieKey &) const;
+    Movie *AddMovie(const MovieKey &);
+
+    const ScheduleDates GetScheduleDates() const;
+    const ScheduleDates GetScheduleDates(const Cinema *) const;
+    const ScheduleDates GetScheduleDates(const Movie *) const;
+    ScheduleEntry FindScheduleEntry(const ScheduleEntryKey &) const;
+    const Schedules GetSchedules() const { _lock.AssertLockedForRead(); return _schedules; }
+    const Schedules GetSchedules(const Cinema *) const;
+    const Schedules GetSchedules(const Movie *) const;
+    const ScheduleKeys GetScheduleKeys(const CinemaKey &) const;
+    const ScheduleKeys GetScheduleKeys(const MovieKey &) const;
+    void AddSchedule(const Cinema *, const Movie *, const QTime &start_time, const QDate &date);
+
+private:
+    AssertedLock _lock;
+    bool _all_cinemas_loaded;
+    Cinemas _cinemas;
+    bool _all_movies_loaded;
+    Movies _movies;
+    Schedules _schedules;
+};
+
+inline int qHash(const QDate &date) { return qHash(date.toJulianDay()); }
+
+#endif // CINEMASCHEDULE_H
diff --git a/src/data/location.cpp b/src/data/location.cpp
new file mode 100644 (file)
index 0000000..8e23fc4
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "location.h"
+
+Location::Location()
+{
+}
+
+bool operator==(const Location &lhs, const Location &rhs)
+{
+    return lhs.GetLocationName() == rhs.GetLocationName();
+}
+
+bool operator!=(const Location &lhs, const Location &rhs)
+{
+    return !(lhs == rhs);
+}
diff --git a/src/data/location.h b/src/data/location.h
new file mode 100644 (file)
index 0000000..1b697d7
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef LOCATION_H
+#define LOCATION_H
+
+#include <QString>
+#include <QMetaType>
+
+class Location
+{
+public:
+    Location();
+
+    bool IsValid() const { return !_location_name.isEmpty(); }
+
+    QString GetLocationName() const { return _location_name; }
+    void SetLocationName(const QString &location_name) { _location_name = location_name; }
+
+private:
+    QString _location_name;
+};
+
+bool operator==(const Location &lhs, const Location &rhs);
+
+bool operator!=(const Location &lhs, const Location &rhs);
+
+Q_DECLARE_METATYPE(Location);
+
+#endif // LOCATION_H
diff --git a/src/data/movie.cpp b/src/data/movie.cpp
new file mode 100644 (file)
index 0000000..ba21b84
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "movie.h"
+
+Movie::Movie()
+    : _rate(-1.0)
+{
+}
diff --git a/src/data/movie.h b/src/data/movie.h
new file mode 100644 (file)
index 0000000..4ea2349
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef MOVIE_H
+#define MOVIE_H
+
+#include "data/moviekey.h"
+
+#include <QString>
+#include <QTime>
+
+class Movie
+{
+public:
+    Movie();
+
+    MovieKey GetKey() const { return MovieKey(_name); }
+
+    QString GetName() const { return _name; }
+    void SetName(const QString &name) { _name = name; }
+
+    QString GetTheatersUrl() const { return _theaters_url; }
+    void SetTheatersUrl(const QString &theaters_url) { _theaters_url = theaters_url; }
+
+    QTime GetDuration() const { return _duration; }
+    void SetDuration(const QTime &duration) { _duration = duration; }
+
+    QString GetComment() const { return _comment; }
+    void SetComment(const QString &age) { _comment = age; }
+
+    double GetRate() const { return _rate; }
+    void SetRate(double rate) { _rate = rate; }
+
+private:
+    QString _name;
+    QString _theaters_url;
+    QTime _duration;
+    QString _comment;
+    double _rate;
+};
+
+#endif // MOVIE_H
diff --git a/src/data/moviekey.cpp b/src/data/moviekey.cpp
new file mode 100644 (file)
index 0000000..b02c88d
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "moviekey.h"
+
+#include <qhash.h>
+
+MovieKey::MovieKey(const QString &name)
+    : _name(name)
+{
+}
+
+bool operator==(const MovieKey &lhs, const MovieKey &rhs)
+{
+    return lhs.GetName() == rhs.GetName();
+}
+
+uint qHash(const MovieKey &key)
+{
+    return qHash(key.GetName());
+}
diff --git a/src/data/moviekey.h b/src/data/moviekey.h
new file mode 100644 (file)
index 0000000..8c85473
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef MOVIEKEY_H
+#define MOVIEKEY_H
+
+#include <QString>
+#include <QMetaType>
+
+class MovieKey
+{
+public:
+    MovieKey() {}
+    MovieKey(const QString &name);
+
+    QString GetName() const { return _name; }
+    void SetName(const QString &name) { _name = name; }
+
+private:
+    QString _name;
+};
+
+bool operator==(const MovieKey &lhs, const MovieKey &rhs);
+
+uint qHash(const MovieKey &);
+
+Q_DECLARE_METATYPE(MovieKey);
+
+#endif // MOVIEKEY_H
diff --git a/src/data/scheduleentry.cpp b/src/data/scheduleentry.cpp
new file mode 100644 (file)
index 0000000..0071dff
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "scheduleentry.h"
+
+#include "data/cinema.h"
+#include "data/movie.h"
+
+#include <qhash.h>
+
+
+ScheduleEntry::ScheduleEntry()
+    : _cinema(0),
+    _movie(0)
+{
+}
+
+ScheduleEntry::ScheduleEntry(const Cinema *cinema, const Movie *movie, const QTime &start_time, const QDate &date)
+    : _cinema(cinema),
+    _movie(movie),
+    _start_time(start_time),
+    _date(date)
+{
+}
+
+ScheduleEntryKey ScheduleEntry::GetKey() const
+{
+    return ScheduleEntryKey(_cinema->GetKey(), _movie->GetKey(), _start_time, _date);
+}
+
+bool operator==(const ScheduleEntry &lhs, const ScheduleEntry &rhs)
+{
+    return lhs.GetCinema() == rhs.GetCinema()
+            && lhs.GetMovie() == rhs.GetMovie()
+            && lhs.GetStartTime() == rhs.GetStartTime()
+            && lhs.GetDate() == rhs.GetDate();
+}
+
+uint qHash(const ScheduleEntry &key)
+{
+    static QTime midnight(0, 0);
+    return qHash(key.GetCinema()) + qHash(key.GetMovie()) + qHash(-key.GetStartTime().secsTo(midnight)) + qHash(key.GetDate().toJulianDay());
+}
diff --git a/src/data/scheduleentry.h b/src/data/scheduleentry.h
new file mode 100644 (file)
index 0000000..9ea8759
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef SCHEDULEENTRY_H
+#define SCHEDULEENTRY_H
+
+#include "scheduleentrykey.h"
+
+#include <QString>
+#include <QDate>
+
+class Cinema;
+class Movie;
+
+class ScheduleEntry
+{
+public:
+    ScheduleEntry();
+    ScheduleEntry(const Cinema *cinema, const Movie *movie, const QTime &start_time, const QDate &date);
+
+    ScheduleEntryKey GetKey() const;
+
+    bool IsValid() const { return _cinema != 0 && _movie != 0; }
+
+    const Cinema *GetCinema() const { return _cinema; }
+    void SetCinema(const Cinema *cinema) { _cinema = cinema; }
+
+    const Movie *GetMovie() const { return _movie; }
+    void SetMovie(const Movie *movie) { _movie = movie; }
+
+    QTime GetStartTime() const { return _start_time; }
+    void SetStartTime(const QTime &start_time) { _start_time = start_time; }
+
+    QDate GetDate() const { return _date; }
+    void SetDate(const QDate &date) { _date = date; }
+
+private:
+    const Cinema *_cinema;
+    const Movie *_movie;
+    QTime _start_time;
+    QDate _date;
+};
+
+bool operator==(const ScheduleEntry &lhs, const ScheduleEntry &rhs);
+
+uint qHash(const ScheduleEntry &);
+
+#endif // SCHEDULEENTRY_H
diff --git a/src/data/scheduleentrykey.cpp b/src/data/scheduleentrykey.cpp
new file mode 100644 (file)
index 0000000..528ac9c
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "scheduleentrykey.h"
+
+#include <qhash.h>
+
+ScheduleEntryKey::ScheduleEntryKey(const CinemaKey &cinema_key, const MovieKey &movie_key, const QTime &start_time, const QDate &date) :
+        _cinema_key(cinema_key),
+        _movie_key(movie_key),
+        _start_time(start_time),
+        _date(date)
+{
+}
+
+bool operator==(const ScheduleEntryKey &lhs, const ScheduleEntryKey &rhs)
+{
+    return lhs.GetCinemaKey() == rhs.GetCinemaKey()
+            && lhs.GetMovieKey() == rhs.GetMovieKey()
+            && lhs.GetStartTime() == rhs.GetStartTime()
+            && lhs.GetDate() == rhs.GetDate();
+}
+
+uint qHash(const ScheduleEntryKey &key)
+{
+    static QTime midnight(0, 0);
+    return qHash(key.GetCinemaKey()) + qHash(key.GetMovieKey()) + qHash(-key.GetStartTime().secsTo(midnight)) + qHash(key.GetDate().toJulianDay());
+}
diff --git a/src/data/scheduleentrykey.h b/src/data/scheduleentrykey.h
new file mode 100644 (file)
index 0000000..110af6e
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef SCHEDULEENTRYKEY_H
+#define SCHEDULEENTRYKEY_H
+
+#include "data/cinemakey.h"
+#include "data/moviekey.h"
+
+#include <QTime>
+#include <QDate>
+#include <QMetaType>
+
+class ScheduleEntryKey
+{
+public:
+    ScheduleEntryKey() {}
+    ScheduleEntryKey(const CinemaKey &cinema_key, const MovieKey &movie_key, const QTime &start_time, const QDate &date);
+
+    CinemaKey GetCinemaKey() const { return _cinema_key; }
+    void SetCinemaKey(const CinemaKey &cinema_key) { _cinema_key = cinema_key; }
+
+    MovieKey GetMovieKey() const { return _movie_key; }
+    void SetMovieKey(const MovieKey &movie_key) { _movie_key = movie_key; }
+
+    QTime GetStartTime() const { return _start_time; }
+    void SetStartTime(const QTime &start_time) { _start_time = start_time; }
+
+    QDate GetDate() const { return _date; }
+    void SetDate(const QDate &date) { _date = date; }
+
+private:
+    CinemaKey _cinema_key;
+    MovieKey _movie_key;
+    QTime _start_time;
+    QDate _date;
+};
+
+Q_DECLARE_METATYPE(ScheduleEntryKey);
+
+bool operator==(const ScheduleEntryKey &lhs, const ScheduleEntryKey &rhs);
+
+uint qHash(const ScheduleEntryKey &);
+
+#endif // SCHEDULEENTRYKEY_H
diff --git a/src/data/settings.cpp b/src/data/settings.cpp
new file mode 100644 (file)
index 0000000..6c1528a
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "settings.h"
+
+Settings::Settings()
+    : _location(),
+    _previous_locations(),
+    _gps_enabled(true),
+    _search_objects_type(MOVIES)
+{
+}
+
+void Settings::SetPreviousLocations(const Locations &previous_locations)
+{
+    _previous_locations = previous_locations;
+}
diff --git a/src/data/settings.h b/src/data/settings.h
new file mode 100644 (file)
index 0000000..d94c76c
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+#include "location.h"
+
+#include <QString>
+#include <QList>
+
+class Settings
+{
+public:
+    typedef QList<Location> Locations;
+
+    enum SearchObjectsType {
+        THEATERS,
+        MOVIES
+    };
+
+public:
+    Settings();
+
+    Location GetLocation() const { return _location; }
+    void SetLocation(const Location &location) { _location = location; }
+
+    Locations GetPreviousLocations() const  { return _previous_locations; }
+    void SetPreviousLocations(const Locations &previous_locations);
+
+    bool IsGPSEnabled() const { return _gps_enabled; }
+    void SetGPSEnabled(bool gps_enabled) { _gps_enabled = gps_enabled; }
+
+    SearchObjectsType GetSearchObjectsType() const { return _search_objects_type; }
+    void SetSearchObjectsType(SearchObjectsType search_objects_type) { _search_objects_type = search_objects_type; }
+
+private:
+    Location _location;
+    Locations _previous_locations;
+    bool _gps_enabled;
+    SearchObjectsType _search_objects_type;
+};
+
+#endif // SETTINGS_H
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644 (file)
index 0000000..645b755
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "movieschedule.h"
+
+int main(int argc, char *argv[])
+{
+    MovieSchedule movie_schedule;
+    int rc = movie_schedule.exec(argc, argv);
+    return rc;
+}
diff --git a/src/movieschedule.cpp b/src/movieschedule.cpp
new file mode 100644 (file)
index 0000000..0063016
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "movieschedule.h"
+
+#include "data/settings.h"
+#include "data/cinemaschedule.h"
+#include "control/settingscontroller.h"
+#include "control/maincontroller.h"
+#include "control/theatercontroller.h"
+#include "control/moviecontroller.h"
+#include "control/locationcontroller.h"
+#include "control/actioncontroller.h"
+#include "control/itemmodelsortcontroller.h"
+#include "ui/mainwindow.h"
+#include "ui/moviemodel.h"
+#include "ui/moviewindow.h"
+#include "ui/theatermodel.h"
+#include "ui/theaterwindow.h"
+#include "ui/ratingprovider.h"
+#include "ui/styleutils.h"
+
+#include <QApplication>
+#include <QTranslator>
+#include <QLocale>
+#include <QThread>
+#include <iostream>
+
+#ifdef MAEMO_SDK
+#include <glib-object.h>
+#endif
+
+#define _STRINGIZE_(x) #x
+#define _STRINGIZE(x) _STRINGIZE_(x)
+
+class ControllerThread : public QThread
+{
+public:
+    void run()
+    {
+        exec();
+    }
+
+    void quit()
+    {
+        QThread::quit();
+        wait();
+    }
+};
+
+MovieSchedule::MovieSchedule()
+{
+}
+
+int MovieSchedule::exec(int argc, char *argv[])
+{
+    QApplication app(argc, argv);
+
+#ifdef MAEMO_SDK
+    g_type_init();
+#endif
+
+    qRegisterMetaType<Location>();
+
+    StyleUtilsSingleton style_utils_singleton;
+    (void) style_utils_singleton;
+
+    QString app_dir;
+#ifdef DEFAULT_PREFIX
+    app_dir = QApplication::applicationDirPath();
+#else
+    app_dir = _STRINGIZE(DATADIR) "/movie-schedule";
+#endif
+    //std::cout << "app_dir = " << qPrintable(app_dir) << std::endl;
+
+    QString locale = QLocale::system().name();
+    //std::cout << "locale: " << qPrintable(locale) << std::endl;
+
+#if 1
+    QTranslator translator;
+    translator.load(app_dir + "/translations/movie-schedule_" + locale);
+    app.installTranslator(&translator);
+#endif
+
+    RatingSingleton rating_singleton;
+    (void) rating_singleton;
+
+    CinemaSchedule cinema_schedule;
+
+    MainWindow main_window(&cinema_schedule);
+    main_window.show();
+
+    Settings settings;
+    SettingsController settings_controller(&settings);
+    settings_controller.Load();
+
+    ActionController action_controller(&cinema_schedule);
+
+    ControllerThread sort_worker;
+    sort_worker.start();
+
+    ControllerThread search_worker;
+    search_worker.start();
+
+    ItemModelSortController sort_controller(&cinema_schedule);
+    sort_controller.moveToThread(&sort_worker);
+
+    TheaterWindow theater_window(&cinema_schedule, &main_window);
+    TheaterController theater_controller(&theater_window, &cinema_schedule, &action_controller,
+                                         &sort_controller, &search_worker);
+
+    MovieWindow movie_window(&cinema_schedule, &main_window);
+    MovieController movie_controller(&movie_window, &cinema_schedule, &action_controller,
+                                     &sort_controller, &search_worker);
+
+    LocationController location_controller(&main_window, &settings);
+
+    MainController main_controller(&main_window, &settings, &cinema_schedule, &theater_controller,
+                                   &movie_controller, &location_controller, &action_controller,
+                                   &sort_controller, &search_worker);
+
+    main_controller.Run();
+
+    int rc = app.exec();
+
+    if (rc == 0) {
+        settings_controller.Save();
+    }
+
+    search_worker.quit();
+
+    sort_worker.quit();
+
+    return rc;
+}
diff --git a/src/movieschedule.h b/src/movieschedule.h
new file mode 100644 (file)
index 0000000..6fee109
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef MOVIESCHEDULE_H
+#define MOVIESCHEDULE_H
+
+#include <QObject>
+
+class MovieSchedule : public QObject
+{
+    Q_OBJECT
+
+public:
+    MovieSchedule();
+
+public:
+    int exec(int argc, char *argv[]);
+
+};
+
+#endif // MOVIESCHEDULE_H
diff --git a/src/resources.qrc b/src/resources.qrc
new file mode 100644 (file)
index 0000000..516293a
--- /dev/null
@@ -0,0 +1,15 @@
+<RCC>
+    <qresource prefix="/">
+        <file>resources/0.png</file>
+        <file>resources/1.png</file>
+        <file>resources/2.png</file>
+        <file>resources/3.png</file>
+        <file>resources/4.png</file>
+        <file>resources/5.png</file>
+        <file>resources/6.png</file>
+        <file>resources/7.png</file>
+        <file>resources/8.png</file>
+        <file>resources/9.png</file>
+        <file>resources/10.png</file>
+    </qresource>
+</RCC>
diff --git a/src/resources/0.png b/src/resources/0.png
new file mode 100644 (file)
index 0000000..88c1cc7
Binary files /dev/null and b/src/resources/0.png differ
diff --git a/src/resources/0.svg b/src/resources/0.svg
new file mode 100644 (file)
index 0000000..bfcf957
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="54"
+   height="10"
+   id="svg2">
+  <defs
+     id="defs4" />
+  <path
+     d="M 8.3937876,9.9252174 L 5.2446694,7.5817439 L 2.0549565,9.8696566 L 3.3106014,6.150494 L 0.14899204,3.8239007 L 4.074141,3.8688056 L 5.3098715,0.14297911 L 6.4801023,3.8898943 L 10.405435,3.9138002 L 7.2035286,6.1846163 L 8.3937876,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path2827" />
+  <path
+     d="M 19.177463,9.9252174 L 16.028344,7.5817439 L 12.838632,9.8696566 L 14.094276,6.150494 L 10.932667,3.8239007 L 14.857815,3.8688056 L 16.093546,0.14297911 L 17.263777,3.8898943 L 21.18911,3.9138002 L 17.987203,6.1846163 L 19.177463,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3714" />
+  <path
+     d="M 29.961137,9.9252174 L 26.812019,7.5817439 L 23.622306,9.8696566 L 24.87795,6.150494 L 21.716342,3.8239007 L 25.64149,3.8688056 L 26.877221,0.14297911 L 28.047452,3.8898943 L 31.972785,3.9138002 L 28.770878,6.1846163 L 29.961137,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3716" />
+  <path
+     d="M 40.744811,9.9252174 L 37.595693,7.5817439 L 34.405981,9.8696566 L 35.661625,6.150494 L 32.500016,3.8239007 L 36.425164,3.8688056 L 37.660895,0.14297911 L 38.831126,3.8898943 L 42.756459,3.9138002 L 39.554552,6.1846163 L 40.744811,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3718" />
+  <path
+     d="M 51.528488,9.9252174 L 48.37937,7.5817439 L 45.189657,9.8696566 L 46.445301,6.150494 L 43.283692,3.8239007 L 47.208841,3.8688056 L 48.444571,0.14297911 L 49.614802,3.8898943 L 53.540135,3.9138002 L 50.338228,6.1846163 L 51.528488,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3720" />
+</svg>
diff --git a/src/resources/1.png b/src/resources/1.png
new file mode 100644 (file)
index 0000000..45648aa
Binary files /dev/null and b/src/resources/1.png differ
diff --git a/src/resources/1.svg b/src/resources/1.svg
new file mode 100644 (file)
index 0000000..9e0a953
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="54"
+   height="10"
+   id="svg2">
+  <defs
+     id="defs4" />
+  <path
+     d="M 5.2839726,0.15169464 L 5.1919919,7.5673741 L 1.9269333,9.8748291 L 3.1417391,6.1047421 L 0.083779711,3.8008 L 3.8538667,3.8426899 L 5.2839726,0.15169464 z "
+     style="fill:yellow;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+     id="path3722" />
+  <path
+     d="M 8.3937876,9.9252174 L 5.2446694,7.5817439 L 2.0549565,9.8696566 L 3.3106014,6.150494 L 0.14899204,3.8239007 L 4.074141,3.8688056 L 5.3098715,0.14297911 L 6.4801023,3.8898943 L 10.405435,3.9138002 L 7.2035286,6.1846163 L 8.3937876,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path2827" />
+  <path
+     d="M 19.177463,9.9252174 L 16.028344,7.5817439 L 12.838632,9.8696566 L 14.094276,6.150494 L 10.932667,3.8239007 L 14.857815,3.8688056 L 16.093546,0.14297911 L 17.263777,3.8898943 L 21.18911,3.9138002 L 17.987203,6.1846163 L 19.177463,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3714" />
+  <path
+     d="M 29.961137,9.9252174 L 26.812019,7.5817439 L 23.622306,9.8696566 L 24.87795,6.150494 L 21.716342,3.8239007 L 25.64149,3.8688056 L 26.877221,0.14297911 L 28.047452,3.8898943 L 31.972785,3.9138002 L 28.770878,6.1846163 L 29.961137,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3716" />
+  <path
+     d="M 40.744811,9.9252174 L 37.595693,7.5817439 L 34.405981,9.8696566 L 35.661625,6.150494 L 32.500016,3.8239007 L 36.425164,3.8688056 L 37.660895,0.14297911 L 38.831126,3.8898943 L 42.756459,3.9138002 L 39.554552,6.1846163 L 40.744811,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3718" />
+  <path
+     d="M 51.528488,9.9252174 L 48.37937,7.5817439 L 45.189657,9.8696566 L 46.445301,6.150494 L 43.283692,3.8239007 L 47.208841,3.8688056 L 48.444571,0.14297911 L 49.614802,3.8898943 L 53.540135,3.9138002 L 50.338228,6.1846163 L 51.528488,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3720" />
+</svg>
diff --git a/src/resources/10.png b/src/resources/10.png
new file mode 100644 (file)
index 0000000..f337945
Binary files /dev/null and b/src/resources/10.png differ
diff --git a/src/resources/10.svg b/src/resources/10.svg
new file mode 100644 (file)
index 0000000..84048aa
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="54"
+   height="10"
+   id="svg2">
+  <defs
+     id="defs4" />
+  <path
+     d="M 8.3937876,9.9252174 L 5.2446694,7.5817439 L 2.0549565,9.8696566 L 3.3106014,6.150494 L 0.14899204,3.8239007 L 4.074141,3.8688056 L 5.3098715,0.14297911 L 6.4801023,3.8898943 L 10.405435,3.9138002 L 7.2035286,6.1846163 L 8.3937876,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path2827" />
+  <path
+     d="M 19.177463,9.9252174 L 16.028344,7.5817439 L 12.838632,9.8696566 L 14.094276,6.150494 L 10.932667,3.8239007 L 14.857815,3.8688056 L 16.093546,0.14297911 L 17.263777,3.8898943 L 21.18911,3.9138002 L 17.987203,6.1846163 L 19.177463,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3714" />
+  <path
+     d="M 29.961137,9.9252174 L 26.812019,7.5817439 L 23.622306,9.8696566 L 24.87795,6.150494 L 21.716342,3.8239007 L 25.64149,3.8688056 L 26.877221,0.14297911 L 28.047452,3.8898943 L 31.972785,3.9138002 L 28.770878,6.1846163 L 29.961137,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3716" />
+  <path
+     d="M 40.744811,9.9252174 L 37.595693,7.5817439 L 34.405981,9.8696566 L 35.661625,6.150494 L 32.500016,3.8239007 L 36.425164,3.8688056 L 37.660895,0.14297911 L 38.831126,3.8898943 L 42.756459,3.9138002 L 39.554552,6.1846163 L 40.744811,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3718" />
+  <path
+     d="M 51.528488,9.9252174 L 48.37937,7.5817439 L 45.189657,9.8696566 L 46.445301,6.150494 L 43.283692,3.8239007 L 47.208841,3.8688056 L 48.444571,0.14297911 L 49.614802,3.8898943 L 53.540135,3.9138002 L 50.338228,6.1846163 L 51.528488,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3720" />
+</svg>
diff --git a/src/resources/2.png b/src/resources/2.png
new file mode 100644 (file)
index 0000000..41884c2
Binary files /dev/null and b/src/resources/2.png differ
diff --git a/src/resources/2.svg b/src/resources/2.svg
new file mode 100644 (file)
index 0000000..c597cda
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="54"
+   height="10"
+   id="svg2">
+  <defs
+     id="defs4" />
+  <path
+     d="M 8.3937876,9.9252174 L 5.2446694,7.5817439 L 2.0549565,9.8696566 L 3.3106014,6.150494 L 0.14899204,3.8239007 L 4.074141,3.8688056 L 5.3098715,0.14297911 L 6.4801023,3.8898943 L 10.405435,3.9138002 L 7.2035286,6.1846163 L 8.3937876,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path2827" />
+  <path
+     d="M 19.177463,9.9252174 L 16.028344,7.5817439 L 12.838632,9.8696566 L 14.094276,6.150494 L 10.932667,3.8239007 L 14.857815,3.8688056 L 16.093546,0.14297911 L 17.263777,3.8898943 L 21.18911,3.9138002 L 17.987203,6.1846163 L 19.177463,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3714" />
+  <path
+     d="M 29.961137,9.9252174 L 26.812019,7.5817439 L 23.622306,9.8696566 L 24.87795,6.150494 L 21.716342,3.8239007 L 25.64149,3.8688056 L 26.877221,0.14297911 L 28.047452,3.8898943 L 31.972785,3.9138002 L 28.770878,6.1846163 L 29.961137,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3716" />
+  <path
+     d="M 40.744811,9.9252174 L 37.595693,7.5817439 L 34.405981,9.8696566 L 35.661625,6.150494 L 32.500016,3.8239007 L 36.425164,3.8688056 L 37.660895,0.14297911 L 38.831126,3.8898943 L 42.756459,3.9138002 L 39.554552,6.1846163 L 40.744811,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3718" />
+  <path
+     d="M 51.528488,9.9252174 L 48.37937,7.5817439 L 45.189657,9.8696566 L 46.445301,6.150494 L 43.283692,3.8239007 L 47.208841,3.8688056 L 48.444571,0.14297911 L 49.614802,3.8898943 L 53.540135,3.9138002 L 50.338228,6.1846163 L 51.528488,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3720" />
+</svg>
diff --git a/src/resources/3.png b/src/resources/3.png
new file mode 100644 (file)
index 0000000..3a467e4
Binary files /dev/null and b/src/resources/3.png differ
diff --git a/src/resources/3.svg b/src/resources/3.svg
new file mode 100644 (file)
index 0000000..75fc022
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="54"
+   height="10"
+   id="svg2">
+  <defs
+     id="defs4" />
+  <path
+     d="M 16.071131,0.15169464 L 15.97915,7.5673741 L 12.714091,9.8748291 L 13.928897,6.1047421 L 10.870938,3.8008 L 14.641025,3.8426899 L 16.071131,0.15169464 z "
+     style="fill:yellow;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+     id="path3722" />
+  <path
+     d="M 8.3937876,9.9252174 L 5.2446694,7.5817439 L 2.0549565,9.8696566 L 3.3106014,6.150494 L 0.14899204,3.8239007 L 4.074141,3.8688056 L 5.3098715,0.14297911 L 6.4801023,3.8898943 L 10.405435,3.9138002 L 7.2035286,6.1846163 L 8.3937876,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path2827" />
+  <path
+     d="M 19.177463,9.9252174 L 16.028344,7.5817439 L 12.838632,9.8696566 L 14.094276,6.150494 L 10.932667,3.8239007 L 14.857815,3.8688056 L 16.093546,0.14297911 L 17.263777,3.8898943 L 21.18911,3.9138002 L 17.987203,6.1846163 L 19.177463,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3714" />
+  <path
+     d="M 29.961137,9.9252174 L 26.812019,7.5817439 L 23.622306,9.8696566 L 24.87795,6.150494 L 21.716342,3.8239007 L 25.64149,3.8688056 L 26.877221,0.14297911 L 28.047452,3.8898943 L 31.972785,3.9138002 L 28.770878,6.1846163 L 29.961137,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3716" />
+  <path
+     d="M 40.744811,9.9252174 L 37.595693,7.5817439 L 34.405981,9.8696566 L 35.661625,6.150494 L 32.500016,3.8239007 L 36.425164,3.8688056 L 37.660895,0.14297911 L 38.831126,3.8898943 L 42.756459,3.9138002 L 39.554552,6.1846163 L 40.744811,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3718" />
+  <path
+     d="M 51.528488,9.9252174 L 48.37937,7.5817439 L 45.189657,9.8696566 L 46.445301,6.150494 L 43.283692,3.8239007 L 47.208841,3.8688056 L 48.444571,0.14297911 L 49.614802,3.8898943 L 53.540135,3.9138002 L 50.338228,6.1846163 L 51.528488,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3720" />
+</svg>
diff --git a/src/resources/4.png b/src/resources/4.png
new file mode 100644 (file)
index 0000000..4e34a64
Binary files /dev/null and b/src/resources/4.png differ
diff --git a/src/resources/4.svg b/src/resources/4.svg
new file mode 100644 (file)
index 0000000..304ea8e
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="54"
+   height="10"
+   id="svg2">
+  <defs
+     id="defs4" />
+  <path
+     d="M 8.3937876,9.9252174 L 5.2446694,7.5817439 L 2.0549565,9.8696566 L 3.3106014,6.150494 L 0.14899204,3.8239007 L 4.074141,3.8688056 L 5.3098715,0.14297911 L 6.4801023,3.8898943 L 10.405435,3.9138002 L 7.2035286,6.1846163 L 8.3937876,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path2827" />
+  <path
+     d="M 19.177463,9.9252174 L 16.028344,7.5817439 L 12.838632,9.8696566 L 14.094276,6.150494 L 10.932667,3.8239007 L 14.857815,3.8688056 L 16.093546,0.14297911 L 17.263777,3.8898943 L 21.18911,3.9138002 L 17.987203,6.1846163 L 19.177463,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3714" />
+  <path
+     d="M 29.961137,9.9252174 L 26.812019,7.5817439 L 23.622306,9.8696566 L 24.87795,6.150494 L 21.716342,3.8239007 L 25.64149,3.8688056 L 26.877221,0.14297911 L 28.047452,3.8898943 L 31.972785,3.9138002 L 28.770878,6.1846163 L 29.961137,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3716" />
+  <path
+     d="M 40.744811,9.9252174 L 37.595693,7.5817439 L 34.405981,9.8696566 L 35.661625,6.150494 L 32.500016,3.8239007 L 36.425164,3.8688056 L 37.660895,0.14297911 L 38.831126,3.8898943 L 42.756459,3.9138002 L 39.554552,6.1846163 L 40.744811,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3718" />
+  <path
+     d="M 51.528488,9.9252174 L 48.37937,7.5817439 L 45.189657,9.8696566 L 46.445301,6.150494 L 43.283692,3.8239007 L 47.208841,3.8688056 L 48.444571,0.14297911 L 49.614802,3.8898943 L 53.540135,3.9138002 L 50.338228,6.1846163 L 51.528488,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3720" />
+</svg>
diff --git a/src/resources/5.png b/src/resources/5.png
new file mode 100644 (file)
index 0000000..b33e5d5
Binary files /dev/null and b/src/resources/5.png differ
diff --git a/src/resources/5.svg b/src/resources/5.svg
new file mode 100644 (file)
index 0000000..76194f1
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="54"
+   height="10"
+   id="svg2">
+  <defs
+     id="defs4" />
+  <path
+     d="M 26.922499,0.15169464 L 26.830518,7.5673741 L 23.565459,9.8748291 L 24.780265,6.1047421 L 21.722306,3.8008 L 25.492393,3.8426899 L 26.922499,0.15169464 z "
+     style="fill:yellow;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+     id="path3722" />
+  <path
+     d="M 8.3937876,9.9252174 L 5.2446694,7.5817439 L 2.0549565,9.8696566 L 3.3106014,6.150494 L 0.14899204,3.8239007 L 4.074141,3.8688056 L 5.3098715,0.14297911 L 6.4801023,3.8898943 L 10.405435,3.9138002 L 7.2035286,6.1846163 L 8.3937876,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path2827" />
+  <path
+     d="M 19.177463,9.9252174 L 16.028344,7.5817439 L 12.838632,9.8696566 L 14.094276,6.150494 L 10.932667,3.8239007 L 14.857815,3.8688056 L 16.093546,0.14297911 L 17.263777,3.8898943 L 21.18911,3.9138002 L 17.987203,6.1846163 L 19.177463,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3714" />
+  <path
+     d="M 29.961137,9.9252174 L 26.812019,7.5817439 L 23.622306,9.8696566 L 24.87795,6.150494 L 21.716342,3.8239007 L 25.64149,3.8688056 L 26.877221,0.14297911 L 28.047452,3.8898943 L 31.972785,3.9138002 L 28.770878,6.1846163 L 29.961137,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3716" />
+  <path
+     d="M 40.744811,9.9252174 L 37.595693,7.5817439 L 34.405981,9.8696566 L 35.661625,6.150494 L 32.500016,3.8239007 L 36.425164,3.8688056 L 37.660895,0.14297911 L 38.831126,3.8898943 L 42.756459,3.9138002 L 39.554552,6.1846163 L 40.744811,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3718" />
+  <path
+     d="M 51.528488,9.9252174 L 48.37937,7.5817439 L 45.189657,9.8696566 L 46.445301,6.150494 L 43.283692,3.8239007 L 47.208841,3.8688056 L 48.444571,0.14297911 L 49.614802,3.8898943 L 53.540135,3.9138002 L 50.338228,6.1846163 L 51.528488,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3720" />
+</svg>
diff --git a/src/resources/6.png b/src/resources/6.png
new file mode 100644 (file)
index 0000000..f674182
Binary files /dev/null and b/src/resources/6.png differ
diff --git a/src/resources/6.svg b/src/resources/6.svg
new file mode 100644 (file)
index 0000000..b247ff2
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="54"
+   height="10"
+   id="svg2">
+  <defs
+     id="defs4" />
+  <path
+     d="M 8.3937876,9.9252174 L 5.2446694,7.5817439 L 2.0549565,9.8696566 L 3.3106014,6.150494 L 0.14899204,3.8239007 L 4.074141,3.8688056 L 5.3098715,0.14297911 L 6.4801023,3.8898943 L 10.405435,3.9138002 L 7.2035286,6.1846163 L 8.3937876,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path2827" />
+  <path
+     d="M 19.177463,9.9252174 L 16.028344,7.5817439 L 12.838632,9.8696566 L 14.094276,6.150494 L 10.932667,3.8239007 L 14.857815,3.8688056 L 16.093546,0.14297911 L 17.263777,3.8898943 L 21.18911,3.9138002 L 17.987203,6.1846163 L 19.177463,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3714" />
+  <path
+     d="M 29.961137,9.9252174 L 26.812019,7.5817439 L 23.622306,9.8696566 L 24.87795,6.150494 L 21.716342,3.8239007 L 25.64149,3.8688056 L 26.877221,0.14297911 L 28.047452,3.8898943 L 31.972785,3.9138002 L 28.770878,6.1846163 L 29.961137,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3716" />
+  <path
+     d="M 40.744811,9.9252174 L 37.595693,7.5817439 L 34.405981,9.8696566 L 35.661625,6.150494 L 32.500016,3.8239007 L 36.425164,3.8688056 L 37.660895,0.14297911 L 38.831126,3.8898943 L 42.756459,3.9138002 L 39.554552,6.1846163 L 40.744811,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3718" />
+  <path
+     d="M 51.528488,9.9252174 L 48.37937,7.5817439 L 45.189657,9.8696566 L 46.445301,6.150494 L 43.283692,3.8239007 L 47.208841,3.8688056 L 48.444571,0.14297911 L 49.614802,3.8898943 L 53.540135,3.9138002 L 50.338228,6.1846163 L 51.528488,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3720" />
+</svg>
diff --git a/src/resources/7.png b/src/resources/7.png
new file mode 100644 (file)
index 0000000..fb87d2e
Binary files /dev/null and b/src/resources/7.png differ
diff --git a/src/resources/7.svg b/src/resources/7.svg
new file mode 100644 (file)
index 0000000..4c06c38
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="54"
+   height="10"
+   id="svg2">
+  <defs
+     id="defs4" />
+  <path
+     d="M 37.709657,0.15169464 L 37.617676,7.5673741 L 34.352617,9.8748291 L 35.567423,6.1047421 L 32.509464,3.8008 L 36.279551,3.8426899 L 37.709657,0.15169464 z "
+     style="fill:yellow;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+     id="path3722" />
+  <path
+     d="M 8.3937876,9.9252174 L 5.2446694,7.5817439 L 2.0549565,9.8696566 L 3.3106014,6.150494 L 0.14899204,3.8239007 L 4.074141,3.8688056 L 5.3098715,0.14297911 L 6.4801023,3.8898943 L 10.405435,3.9138002 L 7.2035286,6.1846163 L 8.3937876,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path2827" />
+  <path
+     d="M 19.177463,9.9252174 L 16.028344,7.5817439 L 12.838632,9.8696566 L 14.094276,6.150494 L 10.932667,3.8239007 L 14.857815,3.8688056 L 16.093546,0.14297911 L 17.263777,3.8898943 L 21.18911,3.9138002 L 17.987203,6.1846163 L 19.177463,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3714" />
+  <path
+     d="M 29.961137,9.9252174 L 26.812019,7.5817439 L 23.622306,9.8696566 L 24.87795,6.150494 L 21.716342,3.8239007 L 25.64149,3.8688056 L 26.877221,0.14297911 L 28.047452,3.8898943 L 31.972785,3.9138002 L 28.770878,6.1846163 L 29.961137,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3716" />
+  <path
+     d="M 40.744811,9.9252174 L 37.595693,7.5817439 L 34.405981,9.8696566 L 35.661625,6.150494 L 32.500016,3.8239007 L 36.425164,3.8688056 L 37.660895,0.14297911 L 38.831126,3.8898943 L 42.756459,3.9138002 L 39.554552,6.1846163 L 40.744811,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3718" />
+  <path
+     d="M 51.528488,9.9252174 L 48.37937,7.5817439 L 45.189657,9.8696566 L 46.445301,6.150494 L 43.283692,3.8239007 L 47.208841,3.8688056 L 48.444571,0.14297911 L 49.614802,3.8898943 L 53.540135,3.9138002 L 50.338228,6.1846163 L 51.528488,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3720" />
+</svg>
diff --git a/src/resources/8.png b/src/resources/8.png
new file mode 100644 (file)
index 0000000..27acdc1
Binary files /dev/null and b/src/resources/8.png differ
diff --git a/src/resources/8.svg b/src/resources/8.svg
new file mode 100644 (file)
index 0000000..0921cf7
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="54"
+   height="10"
+   id="svg2">
+  <defs
+     id="defs4" />
+  <path
+     d="M 8.3937876,9.9252174 L 5.2446694,7.5817439 L 2.0549565,9.8696566 L 3.3106014,6.150494 L 0.14899204,3.8239007 L 4.074141,3.8688056 L 5.3098715,0.14297911 L 6.4801023,3.8898943 L 10.405435,3.9138002 L 7.2035286,6.1846163 L 8.3937876,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path2827" />
+  <path
+     d="M 19.177463,9.9252174 L 16.028344,7.5817439 L 12.838632,9.8696566 L 14.094276,6.150494 L 10.932667,3.8239007 L 14.857815,3.8688056 L 16.093546,0.14297911 L 17.263777,3.8898943 L 21.18911,3.9138002 L 17.987203,6.1846163 L 19.177463,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3714" />
+  <path
+     d="M 29.961137,9.9252174 L 26.812019,7.5817439 L 23.622306,9.8696566 L 24.87795,6.150494 L 21.716342,3.8239007 L 25.64149,3.8688056 L 26.877221,0.14297911 L 28.047452,3.8898943 L 31.972785,3.9138002 L 28.770878,6.1846163 L 29.961137,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3716" />
+  <path
+     d="M 40.744811,9.9252174 L 37.595693,7.5817439 L 34.405981,9.8696566 L 35.661625,6.150494 L 32.500016,3.8239007 L 36.425164,3.8688056 L 37.660895,0.14297911 L 38.831126,3.8898943 L 42.756459,3.9138002 L 39.554552,6.1846163 L 40.744811,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3718" />
+  <path
+     d="M 51.528488,9.9252174 L 48.37937,7.5817439 L 45.189657,9.8696566 L 46.445301,6.150494 L 43.283692,3.8239007 L 47.208841,3.8688056 L 48.444571,0.14297911 L 49.614802,3.8898943 L 53.540135,3.9138002 L 50.338228,6.1846163 L 51.528488,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3720" />
+</svg>
diff --git a/src/resources/9.png b/src/resources/9.png
new file mode 100644 (file)
index 0000000..6f9df0a
Binary files /dev/null and b/src/resources/9.png differ
diff --git a/src/resources/9.svg b/src/resources/9.svg
new file mode 100644 (file)
index 0000000..fc46692
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   version="1.0"
+   width="54"
+   height="10"
+   id="svg2">
+  <defs
+     id="defs4" />
+  <path
+     d="M 48.496815,0.15169464 L 48.404834,7.5673741 L 45.139775,9.8748291 L 46.354581,6.1047421 L 43.296622,3.8008 L 47.066709,3.8426899 L 48.496815,0.15169464 z "
+     style="fill:yellow;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+     id="path3722" />
+  <path
+     d="M 8.3937876,9.9252174 L 5.2446694,7.5817439 L 2.0549565,9.8696566 L 3.3106014,6.150494 L 0.14899204,3.8239007 L 4.074141,3.8688056 L 5.3098715,0.14297911 L 6.4801023,3.8898943 L 10.405435,3.9138002 L 7.2035286,6.1846163 L 8.3937876,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path2827" />
+  <path
+     d="M 19.177463,9.9252174 L 16.028344,7.5817439 L 12.838632,9.8696566 L 14.094276,6.150494 L 10.932667,3.8239007 L 14.857815,3.8688056 L 16.093546,0.14297911 L 17.263777,3.8898943 L 21.18911,3.9138002 L 17.987203,6.1846163 L 19.177463,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3714" />
+  <path
+     d="M 29.961137,9.9252174 L 26.812019,7.5817439 L 23.622306,9.8696566 L 24.87795,6.150494 L 21.716342,3.8239007 L 25.64149,3.8688056 L 26.877221,0.14297911 L 28.047452,3.8898943 L 31.972785,3.9138002 L 28.770878,6.1846163 L 29.961137,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3716" />
+  <path
+     d="M 40.744811,9.9252174 L 37.595693,7.5817439 L 34.405981,9.8696566 L 35.661625,6.150494 L 32.500016,3.8239007 L 36.425164,3.8688056 L 37.660895,0.14297911 L 38.831126,3.8898943 L 42.756459,3.9138002 L 39.554552,6.1846163 L 40.744811,9.9252174 z "
+     style="fill:yellow;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3718" />
+  <path
+     d="M 51.528488,9.9252174 L 48.37937,7.5817439 L 45.189657,9.8696566 L 46.445301,6.150494 L 43.283692,3.8239007 L 47.208841,3.8688056 L 48.444571,0.14297911 L 49.614802,3.8898943 L 53.540135,3.9138002 L 50.338228,6.1846163 L 51.528488,9.9252174 z "
+     style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:0.29798406;stroke-linejoin:round;stroke-miterlimit:1;stroke-dasharray:none;stroke-opacity:1"
+     id="path3720" />
+</svg>
diff --git a/src/searchclients/abstractsearchclient.cpp b/src/searchclients/abstractsearchclient.cpp
new file mode 100644 (file)
index 0000000..dc1219f
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "abstractsearchclient.h"
+
+#include <QMutexLocker>
+#include <iostream>
+
+AbstractSearchClient::AbstractSearchClient(QObject *parent)
+    : QObject(parent),
+    _network(new QNetworkAccessManager(this)),
+    _search_task_id(INVALID_SEARCH_TASK_ID),
+    _start(0)
+{
+    connect(_network, SIGNAL(finished(QNetworkReply *)),
+             this, SLOT(ReplyFinished(QNetworkReply*)));
+    {
+        QMutexLocker locker(&_next_search_task_id_mutex);
+        _search_task_id = _next_search_task_id++;
+    }
+}
+
+AbstractSearchClient::~AbstractSearchClient()
+{
+}
+
+void AbstractSearchClient::Search(const QUrl &url, int start)
+{
+    _start = start;
+    if (start == 0) {
+        emit SearchStarted(_search_task_id);
+    }
+    QNetworkRequest request;
+    QUrl xurl(url);
+    if (_start != 0) {
+        xurl.addQueryItem("start", QString::number(_start));
+    }
+    FixLocation(&xurl);
+    //std::cout << "URL: " << qPrintable(QString(xurl.toEncoded())) << std::endl;
+    request.setUrl(xurl);
+    //request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.9) Gecko/20100401 Ubuntu/9.10 (karmic) Firefox/3.5.9");
+    request.setRawHeader("User-Agent", "Mozilla/5.0");
+    //request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+    request.setRawHeader("Accept", "application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+    request.setRawHeader("Accept-Language", "en-gb;q=1.0,en;q=0.9,de-de;q=0.5,de;q=0.3");
+    //request.setRawHeader("Accept-Encoding", "gzip,deflate");
+    request.setRawHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
+    request.setRawHeader("Keep-Alive", "300");
+    request.setRawHeader("Connection", "keep-alive");
+    request.setRawHeader("Cache-Control", "max-age=0");
+    QNetworkReply *reply = _network->get(request);
+    connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(DownloadProgress(qint64,qint64)));
+    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(NetworkError(QNetworkReply::NetworkError)));
+}
+
+void AbstractSearchClient::DownloadProgress(qint64 a,qint64 b)
+{
+    //std::cout << "Search Progress of " << qPrintable(objectName()) << " - " << a << ", " << b << std::endl;
+    //sleep(1);
+    emit Progress(_search_task_id, a, b);
+}
+
+void AbstractSearchClient::NetworkError(QNetworkReply::NetworkError error)
+{
+    emit SearchFinished(_search_task_id, false);
+    std::cout << "ERROR: " << error << std::endl;
+    emit Error(_search_task_id);
+    sender()->deleteLater();
+    deleteLater();
+}
+
+void AbstractSearchClient::FixLocation(QUrl *url)
+{
+    // Try to fix the Google url which returns
+    // wrong locations in some links
+    if (_location.isNull()) {
+        // Fetch location from url on first call (which is still correct)
+        if (url->hasQueryItem("loc")) {
+            _location = url->queryItemValue("loc");
+        } else if (url->hasQueryItem("near")) {
+            _location = url->queryItemValue("near");
+        } else if (url->hasQueryItem("defaultloc")) {
+            _location = url->queryItemValue("defaultloc");
+        }
+    } else {
+        // Replace with fetched location in later calls
+        if (url->hasQueryItem("loc")) {
+            url->removeAllQueryItems("loc");
+            url->addQueryItem("loc", _location);
+        }
+        if (url->hasQueryItem("near")) {
+            url->removeAllQueryItems("near");
+            url->addQueryItem("near", _location);
+        }
+        if (url->hasQueryItem("defaultloc")) {
+            url->removeAllQueryItems("defaultloc");
+            url->addQueryItem("defaultloc", _location);
+        }
+    }
+}
+
+QMutex AbstractSearchClient::_next_search_task_id_mutex;
+int AbstractSearchClient::_next_search_task_id = 1;
diff --git a/src/searchclients/abstractsearchclient.h b/src/searchclients/abstractsearchclient.h
new file mode 100644 (file)
index 0000000..2cc45bb
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef ABSTRACTSEARCHCLIENT_H
+#define ABSTRACTSEARCHCLIENT_H
+
+#include <QObject>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QMutex>
+
+class AbstractSearchClient : public QObject
+{
+    Q_OBJECT
+public:
+    static const int INVALID_SEARCH_TASK_ID = -1;
+
+public:
+    explicit AbstractSearchClient(QObject *parent = 0);
+    virtual ~AbstractSearchClient();
+
+    int GetSearchTaskId() const { return _search_task_id; }
+
+protected:
+    int GetStartIndex() { return _start; }
+
+    virtual void Search(const QUrl &url, int start);
+
+public:
+    Q_SIGNAL void SearchStarted(int search_task_id);
+    Q_SIGNAL void Progress(int search_task_id, qint64, qint64);
+    Q_SIGNAL void Reply(int search_task_id, bool intermediate);
+    Q_SIGNAL void Error(int search_task_id);
+    Q_SIGNAL void Cancelled(int search_task_id);
+    Q_SIGNAL void SearchFinished(int search_task_id, bool success);
+
+protected:
+    Q_SLOT virtual void ReplyFinished(QNetworkReply *) = 0;
+    Q_SLOT virtual void DownloadProgress(qint64, qint64);
+    Q_SLOT virtual void NetworkError(QNetworkReply::NetworkError);
+
+private:
+    void FixLocation(QUrl *url);
+
+private:
+    QNetworkAccessManager *_network;
+    static QMutex _next_search_task_id_mutex;
+    static int _next_search_task_id;
+    int _search_task_id;
+    int _start;
+    QString _location;
+};
+
+#endif // ABSTRACTSEARCHCLIENT_H
diff --git a/src/searchclients/gpsclient.cpp b/src/searchclients/gpsclient.cpp
new file mode 100644 (file)
index 0000000..18752ed
--- /dev/null
@@ -0,0 +1,247 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "gpsclient.h"
+
+#ifdef QT_MOBILITY_LOCATION
+#include <QGeoPositionInfoSource>
+#endif
+
+#ifdef LIBLOCATION
+#include <QTimer>
+#endif
+
+#include <QUrl>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QMutexLocker>
+#include <iostream>
+
+#ifdef LIBLOCATION
+static void changed(LocationGPSDevice *device, gpointer userdata)
+{
+    Q_UNUSED(device);
+    ((GpsClient *) userdata)->GpsChanged();
+}
+
+static void connected(LocationGPSDevice *device, gpointer userdata)
+{
+    Q_UNUSED(device);
+    ((GpsClient *) userdata)->GpsConnected();
+}
+
+static void disconnected(LocationGPSDevice *device, gpointer userdata)
+{
+    Q_UNUSED(device);
+    ((GpsClient *) userdata)->GpsDisconnected();
+}
+#endif
+
+GpsClient::GpsClient()
+    :
+#ifdef QT_MOBILITY_LOCATION
+    _geo_position_info_source(QGeoPositionInfoSource::createDefaultSource(this)),
+#endif
+#ifdef LIBLOCATION
+    _location_gpsd_control(0),
+    _location_gps_device(0),
+    _time_out_timer(new QTimer(this)),
+#endif
+    _network(new QNetworkAccessManager(this)),
+    _search_task_id(INVALID_SEARCH_TASK_ID)
+{
+    {
+        QMutexLocker locker(&_next_search_task_id_mutex);
+        _search_task_id = _next_search_task_id++;
+    }
+#ifdef QT_MOBILITY_LOCATION
+    connect(_geo_position_info_source, SIGNAL(positionUpdated(QGeoPositionInfo)), this, SLOT(GeoPositionUpdated(const QGeoPositionInfo &)));
+    connect(_geo_position_info_source, SIGNAL(updateTimeout()), this, SLOT(GeoPositionTimedOut()));
+#endif
+#ifdef LIBLOCATION
+    connect(_time_out_timer, SIGNAL(timeout()), this, SLOT(GpsTimedOut()));
+#endif
+    connect(_network, SIGNAL(finished(QNetworkReply*)), this, SLOT(ReplyFinished(QNetworkReply*)));
+}
+
+GpsClient::~GpsClient()
+{
+#ifdef LIBLOCATION
+    if (_location_gps_device != 0)
+        g_object_unref(_location_gps_device);
+    if (_location_gpsd_control != 0)
+        location_gpsd_control_stop(_location_gpsd_control);
+#endif
+}
+
+void GpsClient::SearchLocation()
+{
+    _semaphore.Activate(GetSearchTaskId());
+#ifdef QT_MOBILITY_LOCATION
+    _geo_position_info_source->requestUpdate(30 * 1000);
+    emit SearchStarted(GetSearchTaskId());
+#elif defined(LIBLOCATION)
+    _location_gpsd_control = location_gpsd_control_get_default();
+    if (_location_gpsd_control != 0) {
+        location_gpsd_control_start(_location_gpsd_control);
+    }
+    emit SearchStarted(GetSearchTaskId());
+    _location_gps_device = (LocationGPSDevice *) g_object_new(LOCATION_TYPE_GPS_DEVICE, NULL);
+    if (_location_gps_device != 0) {
+        location_gps_device_reset_last_known(_location_gps_device);
+        g_signal_connect(_location_gps_device, "changed", G_CALLBACK(changed), this);
+        g_signal_connect(_location_gps_device, "connected", G_CALLBACK(connected), this);
+        g_signal_connect(_location_gps_device, "disconnected", G_CALLBACK(disconnected), this);
+    }
+    _time_out_timer->start(30 * 1000);
+#else
+    emit SearchStarted(GetSearchTaskId());
+    emit SearchError(GetSearchTaskId());
+    emit SearchFinished(GetSearchTaskId(), false);
+    deleteLater();
+#endif
+}
+
+void GpsClient::CancelAllRunningSearchs()
+{
+    _semaphore.CancelAll();
+}
+
+#ifdef QT_MOBILITY_LOCATION
+void GpsClient::GeoPositionUpdated(const QGeoPositionInfo &geo_position_info)
+{
+    if (geo_position_info.coordinate().isValid()) {
+        //std::cout << "longitude " << geo_position_info.coordinate().longitude()
+        //        << ", latitude " << geo_position_info.coordinate().latitude()
+        //        << ", altitude " << geo_position_info.coordinate().altitude()
+        //        << std::endl;
+        SearchTown(QString("%1").arg(geo_position_info.coordinate().longitude()),
+                   QString("%1").arg(geo_position_info.coordinate().latitude()));
+        emit SearchForTownStarted(GetSearchTaskId());
+    } else {
+        //std::cout << "invalid coordinate received" << std::endl;
+        emit SearchError(GetSearchTaskId());
+        emit SearchFinished(GetSearchTaskId(), false);
+        deleteLater();
+    }
+}
+
+void GpsClient::GeoPositionTimedOut()
+{
+    //std::cout << "time-out" << std::endl;
+    emit SearchError(GetSearchTaskId());
+    emit SearchFinished(GetSearchTaskId(), false);
+    deleteLater();
+}
+#endif
+
+#ifdef LIBLOCATION
+void GpsClient::GpsConnected()
+{
+    //std::cout << "connected" << std::endl;
+}
+
+void GpsClient::GpsChanged()
+{
+    if (_location_gps_device->status == LOCATION_GPS_DEVICE_STATUS_FIX
+        && _location_gps_device->fix != 0
+        && (_location_gps_device->fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET) != 0)
+    {
+        //std::cout << "longitude " << _location_gps_device->fix->longitude
+        //        << ", latitude " << _location_gps_device->fix->latitude
+        //        << ", altitude " << _location_gps_device->fix->altitude
+        //        << ", eph " << _location_gps_device->fix->eph
+        //        << std::endl;
+        if (_location_gps_device->fix->eph != LOCATION_GPS_DEVICE_NAN
+            && _location_gps_device->fix->eph <= (20 * 1000 * 100)) // 20km
+        {
+            SearchTown(QString("%1").arg(_location_gps_device->fix->longitude),
+                       QString("%1").arg(_location_gps_device->fix->latitude));
+            emit SearchForTownStarted(GetSearchTaskId());
+        } else {
+            //std::cout << "waiting for better accuracy" << std::endl;
+        }
+    } else {
+        //std::cout << "waiting for location" << std::endl;
+    }
+}
+
+void GpsClient::GpsDisconnected()
+{
+    //std::cout << "disconnected" << std::endl;
+}
+
+void GpsClient::GpsTimedOut()
+{
+    //std::cout << "time-out" << std::endl;
+    emit SearchError(GetSearchTaskId());
+    emit SearchFinished(GetSearchTaskId(), false);
+    deleteLater();
+}
+#endif
+
+void GpsClient::SearchTown(const QString &longitude, const QString &latitude)
+{
+    // TODO: try to fetch a unique city name, at least with country code.
+    // http://code.google.com/intl/en/apis/maps/documentation/geocoding/index.html#ReverseGeocoding
+    QUrl url("http://maps.google.com/maps/geo");
+    url.addEncodedQueryItem("q", QUrl::toPercentEncoding(latitude + "," + longitude));
+    url.addEncodedQueryItem("output", QUrl::toPercentEncoding("xml"));
+    _network->get(QNetworkRequest(url));
+}
+
+void GpsClient::ReplyFinished(QNetworkReply *network_reply)
+{
+    if (!network_reply->error()) {
+        QString data = QString::fromUtf8(network_reply->readAll());
+        int start = data.indexOf("<LocalityName>");
+        if (start >= 0) {
+            int end = data.indexOf("</LocalityName>", start);
+            QString town = data.mid(start + 14, end - start - 14);
+            if (!town.isEmpty()) {
+                //std::cout << "Found town " << qPrintable(town) << std::endl;
+                emit TownUpdate(GetSearchTaskId(), town);
+                emit SearchFinished(GetSearchTaskId(), true);
+                deleteLater();
+            } else {
+                //std::cout << "No town found in " << qPrintable(data) << std::endl;
+                emit SearchError(GetSearchTaskId());
+                emit SearchFinished(GetSearchTaskId(), false);
+                deleteLater();
+            }
+        } else {
+            //std::cout << "No <LocalityName> found in " << qPrintable(data) << std::endl;
+            emit SearchError(GetSearchTaskId());
+            emit SearchFinished(GetSearchTaskId(), false);
+            deleteLater();
+        }
+    }
+    network_reply->deleteLater();
+}
+
+void GpsClient::NetworkError(QNetworkReply::NetworkError)
+{
+    //std::cout << "Network error" << std::endl;
+    emit SearchError(GetSearchTaskId());
+    emit SearchFinished(GetSearchTaskId(), false);
+    deleteLater();
+}
+
+QMutex GpsClient::_next_search_task_id_mutex;
+int GpsClient::_next_search_task_id = 1;
+SearchClientSemaphore GpsClient::_semaphore;
diff --git a/src/searchclients/gpsclient.h b/src/searchclients/gpsclient.h
new file mode 100644 (file)
index 0000000..f25ac5b
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef GPSCLIENT_H
+#define GPSCLIENT_H
+
+#include "searchclientsemaphore.h"
+
+#include <QObject>
+#include <QMutex>
+#include <QNetworkReply>
+
+class QNetworkAccessManager;
+
+#ifdef QT_MOBILITY_LOCATION
+#include <qmobilityglobal.h>
+
+QTM_BEGIN_NAMESPACE
+        class QGeoPositionInfo;
+class QGeoPositionInfoSource;
+QTM_END_NAMESPACE;
+
+QTM_USE_NAMESPACE;
+#endif
+
+#ifdef LIBLOCATION
+extern "C" {
+#include <location/location-gps-device.h>
+#include <location/location-gpsd-control.h>
+}
+class QTimer;
+#endif
+
+class GpsClient : public QObject
+{
+    Q_OBJECT
+public:
+    static const int INVALID_SEARCH_TASK_ID = -1;
+
+public:
+    GpsClient();
+    ~GpsClient();
+
+public:
+    int GetSearchTaskId() const { return _search_task_id; }
+
+    void SearchLocation();
+
+    static void CancelAllRunningSearchs();
+
+public:
+    Q_SIGNAL void SearchStarted(int search_task_id);
+    Q_SIGNAL void PositionUpdate(int search_task_id);
+    Q_SIGNAL void SearchForTownStarted(int search_task_id);
+    Q_SIGNAL void TownUpdate(int search_task_id, QString town);
+    Q_SIGNAL void SearchError(int search_task_id);
+    Q_SIGNAL void SearchFinished(int search_task_id, bool success);
+
+private:
+#ifdef QT_MOBILITY_LOCATION
+    Q_SLOT void GeoPositionUpdated(const QGeoPositionInfo &);
+    Q_SLOT void GeoPositionTimedOut();
+#endif
+
+#ifdef LIBLOCATION
+public:
+    void GpsConnected();
+    void GpsChanged();
+    void GpsDisconnected();
+    Q_SLOT void GpsTimedOut();
+#endif
+
+private:
+    void SearchTown(const QString &longitude, const QString &latitude);
+    Q_SLOT void ReplyFinished(QNetworkReply *);
+    Q_SLOT void NetworkError(QNetworkReply::NetworkError);
+
+private:
+#ifdef QT_MOBILITY_LOCATION
+    QGeoPositionInfoSource *_geo_position_info_source;
+#endif
+
+#ifdef LIBLOCATION
+    LocationGPSDControl *_location_gpsd_control;
+    LocationGPSDevice *_location_gps_device;
+    QTimer *_time_out_timer;
+#endif
+
+    QNetworkAccessManager *_network;
+    static QMutex _next_search_task_id_mutex;
+    static int _next_search_task_id;
+    int _search_task_id;
+    static SearchClientSemaphore _semaphore;
+};
+
+#endif // GPSCLIENT_H
diff --git a/src/searchclients/movieschedulesearchclient.cpp b/src/searchclients/movieschedulesearchclient.cpp
new file mode 100644 (file)
index 0000000..cb2ac42
--- /dev/null
@@ -0,0 +1,231 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "movieschedulesearchclient.h"
+
+#include "data/cinemaschedule.h"
+#include "data/cinema.h"
+#include "data/scheduleentry.h"
+#include "data/movie.h"
+#include "utils/timeutils.h"
+#include "utils/assertedlocker.h"
+
+#include <QXmlStreamReader>
+#include <QRegExp>
+#include <QUrl>
+#include <iostream>
+
+MovieScheduleSearchClient::MovieScheduleSearchClient(CinemaSchedule *cinema_schedule, QObject *parent)
+    : AbstractSearchClient(parent),
+    _cinema_schedule(cinema_schedule)
+{
+}
+
+void MovieScheduleSearchClient::SearchSchedule(const MovieKey &movie_key, const QString &url)
+{
+    setObjectName(QString("MovieScheduleSearchClient:%1").arg(movie_key.GetName()));
+    _semaphore.Activate(GetSearchTaskId());
+    _movie_key = movie_key;
+    _date = QDate::currentDate();
+    _url = QUrl::fromEncoded(QString("http://www.google.com" + url).toAscii(), QUrl::TolerantMode);
+    _dates_seen.clear();
+    _dates_seen.insert("0");
+    _date_urls.clear();
+    Search(0);
+}
+
+void MovieScheduleSearchClient::CancelAllRunningSearchs()
+{
+    _semaphore.CancelAll();
+}
+
+void MovieScheduleSearchClient::Search(int start)
+{
+    AbstractSearchClient::Search(_url, start);
+}
+
+void MovieScheduleSearchClient::SearchNextDate()
+{
+    if (_date_urls.isEmpty()) {
+        return;
+    }
+    QPair<QUrl, QDate> pair = _date_urls.dequeue();
+    _date = pair.second;
+    _url = pair.first;
+    Search(0);
+}
+
+enum State {
+    PARSE_HTML,
+    PARSE_DATE_LINK,
+    PARSE_THEATER_DIV,
+    PARSE_THEATER_LINK,
+    PARSE_PHONE_LINK,
+    PARSE_LINK,
+    PARSE_BR,
+    PARSE_SPAN,
+};
+
+void MovieScheduleSearchClient::ReplyFinished(QNetworkReply *reply)
+{
+    //std::cout << "REPLY" << std::endl;
+    //std::cout << reply->readAll().data() << std::endl;
+    QXmlStreamReader xml(reply);
+    State state = PARSE_HTML;
+    int found = 0;
+    QString theater_name;
+    QString theater_address;
+    QString theater_phone;
+    QList<QTime> schedule;
+    QRegExp time_pattern("\\d+:\\d+([aApP][mM])*");
+    while (!xml.atEnd()) {
+        QXmlStreamReader::TokenType token = xml.readNext();
+        if (token == QXmlStreamReader::StartElement) {
+            QString attr_href = xml.attributes().value("href").toString();
+            //std::cout << qPrintable(xml.name().toString()) << ", class " << qPrintable(attr_class) << ", href " << qPrintable(attr_href) << std::endl;
+            if (state == PARSE_HTML && xml.name() == "a" && attr_href.startsWith("/m/movies")) {
+                QUrl url = QUrl::fromEncoded(QString("http://www.google.com" + attr_href).toAscii(), QUrl::TolerantMode);
+                //std::cout << "LINK " << qPrintable(attr_href) << std::endl;
+                if (url.hasQueryItem("date")) {
+                    QString v = url.queryItemValue("date");
+                    std::cout << "FOUND Date Link " << qPrintable(v) << " from " << qPrintable(url.toString()) << std::endl;
+                    if (!_dates_seen.contains(v)) {
+                        // TODO replace location with user selected location (Google simplifies to much)
+                        _dates_seen.insert(v);
+                        _date_urls.append(qMakePair(url, QDate::currentDate().addDays(v.toInt())));
+                    }
+                    state = PARSE_DATE_LINK;
+                } else if (url.hasQueryItem("tid")) {
+                    theater_name = "";
+                    theater_address = "";
+                    theater_phone = "";
+                    schedule.clear();
+                    state = PARSE_THEATER_LINK;
+                } else {
+                    state = PARSE_HTML;
+                }
+            } else if (state == PARSE_THEATER_DIV && xml.name() == "a") {
+                if (attr_href.startsWith("wtai:")) {
+                    state = PARSE_PHONE_LINK;
+                } else {
+                    state = PARSE_LINK;
+                }
+            } else if (state == PARSE_THEATER_DIV && xml.name() == "br") {
+                state = PARSE_BR;
+            } else if (state == PARSE_THEATER_DIV && xml.name() == "span") {
+                state = PARSE_SPAN;
+            } else {
+                state = PARSE_HTML;
+            }
+        } else if (token == QXmlStreamReader::EndElement) {
+            if (state == PARSE_DATE_LINK) {
+                state = PARSE_HTML;
+            } else if (state == PARSE_THEATER_LINK) {
+                state = PARSE_THEATER_DIV;
+            } else if (state == PARSE_BR) {
+                state = PARSE_THEATER_DIV;
+            } else if (state == PARSE_SPAN) {
+                state = PARSE_THEATER_DIV;
+            } else if (state == PARSE_LINK) {
+                state = PARSE_THEATER_DIV;
+            } else if (state == PARSE_PHONE_LINK) {
+                state = PARSE_THEATER_DIV;
+            } else if (state == PARSE_THEATER_DIV) {
+                state = PARSE_HTML;
+                if (!theater_name.isEmpty()) {
+                    ++found;
+                    if (!schedule.isEmpty()) {
+                        AssertedWriteLocker locker(_cinema_schedule->GetLock());
+                        if (!_semaphore.IsActive(GetSearchTaskId())) {
+                            break;
+                        }
+                        const Movie *movie = _cinema_schedule->FindMovie(_movie_key);
+                        if (movie != 0) {
+                            //std::cout << "ADD SCHEDULE " << qPrintable(theater_name) << ", " << qPrintable(theater_address) << std::endl;
+                            CinemaKey key(theater_name, theater_address);
+                            Cinema *cinema = _cinema_schedule->FindCinema(key);
+                            if (cinema == 0) {
+                                cinema = _cinema_schedule->AddCinema(key);
+                            }
+                            if (!theater_phone.isEmpty()) {
+                                cinema->SetTelephone(theater_phone);
+                            }
+                            Q_FOREACH(const QTime time, schedule) {
+                                _cinema_schedule->AddSchedule(cinema, movie, time, _date);
+                            }
+                        }
+                    }
+                }
+            }
+        } else if (token == QXmlStreamReader::Characters) {
+            if (state == PARSE_THEATER_LINK) {
+                //std::cout << "name " << qPrintable(xml.text().toString()) << std::endl;
+                theater_name = xml.text().toString();
+            } else if (state == PARSE_PHONE_LINK) {
+                //std::cout << "phone " << qPrintable(xml.text().toString()) << std::endl;
+                theater_phone = xml.text().toString();
+            } else if (state == PARSE_SPAN) {
+                QString t = xml.text().toString();
+                int i = 0;
+                bool found = false;
+                while ((i = time_pattern.indexIn(t, i)) != -1) {
+                    int length = time_pattern.matchedLength();
+                    //std::cout << "time " << qPrintable(t.mid(i, length)) << std::endl;
+                    QTime time = TimeUtils::FromTimeString(t.mid(i, length));
+                    if (time.isValid()) {
+                        schedule.append(time);
+                    } else {
+                        std::cout << "ERROR: time " << qPrintable(t.mid(i, length)) << " is invalid." << std::endl;
+                    }
+                    i += length;
+                    found = true;
+                }
+                if (!found) {
+                    //std::cout << "address " << qPrintable(t) << std::endl;
+                    theater_address = t;
+                }
+            }
+        }
+    }
+    if (xml.hasError()) {
+        emit SearchFinished(GetSearchTaskId(), false);
+        std::cout << "xml error (" << xml.lineNumber() << "/" << xml.columnNumber() << "): " << qPrintable(xml.errorString()) << std::endl;
+        emit Error(GetSearchTaskId());
+        deleteLater();
+    } else if (!_semaphore.IsActive(GetSearchTaskId())) {
+        emit Cancelled(GetSearchTaskId());
+        emit SearchFinished(GetSearchTaskId(), false);
+        deleteLater();
+    } else {
+        if (found > 0) {
+            emit Reply(GetSearchTaskId(), true);
+            Search(GetStartIndex() + found);
+        } else {
+            if (!_date_urls.isEmpty()) {
+                SearchNextDate();
+            } else {
+                emit Reply(GetSearchTaskId(), false);
+                emit SearchFinished(GetSearchTaskId(), true);
+                deleteLater();
+            }
+        }
+    }
+    reply->deleteLater();
+    //std::cout << "REPLY FINISHED" << std::endl;
+}
+
+SearchClientSemaphore MovieScheduleSearchClient::_semaphore;
diff --git a/src/searchclients/movieschedulesearchclient.h b/src/searchclients/movieschedulesearchclient.h
new file mode 100644 (file)
index 0000000..5d3bcf2
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef MOVIESCHEDULESEARCHCLIENT_H
+#define MOVIESCHEDULESEARCHCLIENT_H
+
+#include "abstractsearchclient.h"
+#include "searchclientsemaphore.h"
+#include "data/moviekey.h"
+
+#include <QUrl>
+#include <QQueue>
+#include <QSet>
+#include <QPair>
+#include <QDate>
+
+class CinemaSchedule;
+class Movie;
+
+class MovieScheduleSearchClient : public AbstractSearchClient
+{
+    Q_OBJECT
+public:
+    explicit MovieScheduleSearchClient(CinemaSchedule *cinema_schedule, QObject *parent = 0);
+
+    void SearchSchedule(const MovieKey &movie_key, const QString &url);
+
+    static void CancelAllRunningSearchs();
+
+private:
+    void Search(int start);
+    void SearchNextDate();
+    Q_SLOT virtual void ReplyFinished(QNetworkReply *);
+
+private:
+    CinemaSchedule *_cinema_schedule;
+    MovieKey _movie_key;
+    QDate _date;
+    QUrl _url;
+    QSet<QString> _dates_seen;
+    QQueue<QPair<QUrl, QDate> > _date_urls;
+    static SearchClientSemaphore _semaphore;
+};
+
+#endif // MOVIESCHEDULESEARCHCLIENT_H
diff --git a/src/searchclients/moviesearchclient.cpp b/src/searchclients/moviesearchclient.cpp
new file mode 100644 (file)
index 0000000..670c569
--- /dev/null
@@ -0,0 +1,193 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "moviesearchclient.h"
+
+#include "data/cinemaschedule.h"
+#include "data/movie.h"
+#include "data/moviekey.h"
+#include "utils/assertedlocker.h"
+
+#include <QXmlStreamReader>
+#include <QRegExp>
+#include <iostream>
+
+MovieSearchClient::MovieSearchClient(CinemaSchedule *cinema_schedule, QObject *parent)
+    : AbstractSearchClient(parent),
+    _cinema_schedule(cinema_schedule)
+{
+}
+
+void MovieSearchClient::SearchMovie(const QString &town)
+{
+    _semaphore.Activate(GetSearchTaskId());
+    setObjectName(QString("MovieSearchClient:%1").arg(town));
+    _town = town;
+    Search(0);
+}
+
+void MovieSearchClient::CancelAllRunningSearchs()
+{
+    _semaphore.CancelAll();
+}
+
+void MovieSearchClient::Search(int start)
+{
+    QUrl url("http://www.google.com/m/movies");
+    url.addQueryItem("loc", _town);
+    url.addQueryItem("sort", QString::number(1));
+    AbstractSearchClient::Search(url, start);
+}
+
+enum State {
+    PARSE_HTML,
+    PARSE_MOVIE_LINK,
+    PARSE_EXPECT_DIV1,
+    PARSE_EXPECT_DIV2, PARSE_DIV2,
+    PARSE_SPAN, PARSE_RATING, PARSE_TRAILER
+};
+
+void MovieSearchClient::ReplyFinished(QNetworkReply *reply)
+{
+    //std::cout << qPrintable(QString(reply->readAll())) << std::endl;
+    QXmlStreamReader xml(reply);
+    State state = PARSE_HTML;
+    int found = 0;
+    QString movie_name;
+    QVector<QString> movie_spans;
+    double movie_rating = -1.0;
+    QString movie_theaters_url;
+    QRegExp duration_pattern("((\\d+)hr )?(\\d+)min");
+    QRegExp reviews_pattern("\\d+ review(s)?");
+    while (!xml.atEnd()) {
+        QXmlStreamReader::TokenType token = xml.readNext();
+        if (token == QXmlStreamReader::StartElement) {
+            QString attr_class = xml.attributes().value("class").toString();
+            QString attr_href = xml.attributes().value("href").toString();
+            //std::cout << "tag = " << qPrintable(xml.name().toString()) << ", class = " << qPrintable(attr_class) << ", href = " << qPrintable(attr_href) << std::endl;
+            if (state == PARSE_HTML && xml.name() == "a" && attr_href.startsWith("/m/movies")) {
+                QUrl url = QUrl::fromEncoded(QString("http://www.google.com" + attr_href).toAscii(), QUrl::TolerantMode);
+                //std::cout << "LINK " << qPrintable(attr_href) << std::endl;
+                if (url.hasQueryItem("mid")) {
+                    movie_name = "";
+                    movie_spans.clear();
+                    movie_rating = -1.0;
+                    movie_theaters_url = attr_href;
+                    state = PARSE_MOVIE_LINK;
+                } else {
+                    state = PARSE_HTML;
+                }
+            } else if (state == PARSE_EXPECT_DIV2 && xml.name() == "div") {
+                state = PARSE_DIV2;
+            } else if (state == PARSE_DIV2 && xml.name() == "span" && attr_class.isEmpty()) {
+                movie_spans.append("");
+                state = PARSE_SPAN;
+            } else if (state == PARSE_DIV2 && xml.name() == "img") {
+                movie_rating = (double) xml.attributes().value("src").at(41).digitValue() / 10.0;
+                //std::cout << "rating: " << movie_rating << std::endl;
+                state = PARSE_RATING;
+            } else if (state == PARSE_DIV2 && xml.name() == "a") {
+                state = PARSE_TRAILER;
+            } else if (state != PARSE_HTML) {
+                state = PARSE_HTML;
+            }
+        } else if (token == QXmlStreamReader::EndElement) {
+            if (state == PARSE_MOVIE_LINK) {
+                state = PARSE_EXPECT_DIV1;
+            } else if (state == PARSE_EXPECT_DIV1) {
+                state = PARSE_EXPECT_DIV2;
+            } else if (state == PARSE_EXPECT_DIV2) {
+                state = PARSE_HTML;
+            } else if (state == PARSE_SPAN) {
+                state = PARSE_DIV2;
+            } else if (state == PARSE_RATING) {
+                state = PARSE_DIV2;
+            } else if (state == PARSE_TRAILER) {
+                state = PARSE_DIV2;
+            } else if (state == PARSE_DIV2) {
+                if (!movie_name.isEmpty()) {
+                    AssertedWriteLocker locker(_cinema_schedule->GetLock());
+                    if (!_semaphore.IsActive(GetSearchTaskId())) {
+                        break;
+                    }
+                    //std::cout << "ADD MOVIE " << qPrintable(movie_name) << std::endl;
+                    ++found;
+                    MovieKey key(movie_name);
+                    Movie *movie = _cinema_schedule->FindMovie(key);
+                    if (movie == 0) {
+                        movie = _cinema_schedule->AddMovie(key);
+                    }
+                    if (!movie_theaters_url.isEmpty()) {
+                        movie->SetTheatersUrl(movie_theaters_url);
+                    }
+                    if (movie_rating >= 0.0) {
+                        movie->SetRate(movie_rating);
+                    }
+                    Q_FOREACH (QString s, movie_spans) {
+                        if (duration_pattern.exactMatch(s)) {
+                            QString hours = duration_pattern.cap(2);
+                            QString minutes = duration_pattern.cap(3);
+                            //std::cout << "hours = " << qPrintable(hours) << ", minutes = " << qPrintable(minutes) << ",0: " << qPrintable(duration_pattern.cap(0)) << ", 1: " << qPrintable(duration_pattern.cap(1)) << std::endl;
+                            movie->SetDuration(QTime(hours.toInt(), minutes.toInt()));
+                        } else if (reviews_pattern.exactMatch(s)) {
+                            // Ignore number of reviews
+                        } else {
+                            movie->SetComment(s);
+                        }
+                    }
+                }
+                state = PARSE_HTML;
+            }
+        } else if (token == QXmlStreamReader::Characters) {
+            if (state == PARSE_MOVIE_LINK) {
+                //std::cout << "movie: " << qPrintable(xml.text().toString()) << std::endl;
+                movie_name = xml.text().toString();
+            } else if (state == PARSE_SPAN) {
+                int i = movie_spans.size()-1;
+                if (movie_spans[i].isEmpty()) {
+                    movie_spans[i] = xml.text().toString();
+                } else if (!xml.text().isEmpty()) {
+                    movie_spans[i] += " ";
+                    movie_spans[i] += xml.text().toString();
+                }
+                //std::cout << " span: " << qPrintable(movie_spans[i]) << std::endl;
+            }
+        }
+    }
+    if (xml.hasError()) {
+        std::cout << "xml error (" << xml.lineNumber() << "/" << xml.columnNumber() << "): " << qPrintable(xml.errorString()) << std::endl;
+        emit Error(GetSearchTaskId());
+        emit SearchFinished(GetSearchTaskId(), false);
+        deleteLater();
+    } else if (!_semaphore.IsActive(GetSearchTaskId())) {
+        emit Cancelled(GetSearchTaskId());
+        emit SearchFinished(GetSearchTaskId(), false);
+        deleteLater();
+    } else {
+        if (found > 0) {
+            emit Reply(GetSearchTaskId(), true);
+            Search(GetStartIndex() + found);
+        } else {
+            emit Reply(GetSearchTaskId(), false);
+            emit SearchFinished(GetSearchTaskId(), true);
+            deleteLater();
+        }
+    }
+    reply->deleteLater();
+}
+
+SearchClientSemaphore MovieSearchClient::_semaphore;
diff --git a/src/searchclients/moviesearchclient.h b/src/searchclients/moviesearchclient.h
new file mode 100644 (file)
index 0000000..486182b
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef MOVIESEARCHCLIENT_H
+#define MOVIESEARCHCLIENT_H
+
+#include "abstractsearchclient.h"
+#include "searchclientsemaphore.h"
+
+class CinemaSchedule;
+
+class MovieSearchClient : public AbstractSearchClient
+{
+    Q_OBJECT
+public:
+    explicit MovieSearchClient(CinemaSchedule *cinema_schedule, QObject *parent = 0);
+
+    void SearchMovie(const QString &town);
+
+    static void CancelAllRunningSearchs();
+
+private:
+    void Search(int start);
+    Q_SLOT virtual void ReplyFinished(QNetworkReply *);
+
+private:
+    CinemaSchedule *_cinema_schedule;
+    QString _town;
+    static SearchClientSemaphore _semaphore;
+};
+
+#endif // MOVIESEARCHCLIENT_H
diff --git a/src/searchclients/searchclientsemaphore.cpp b/src/searchclients/searchclientsemaphore.cpp
new file mode 100644 (file)
index 0000000..00e1205
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "searchclientsemaphore.h"
+
+static const int INVALID_ID = -1;
+
+SearchClientSemaphore::SearchClientSemaphore()
+    : _mutex(),
+    _active_search_task_id(INVALID_ID)
+{
+}
+
+void SearchClientSemaphore::Activate(int search_task_id)
+{
+    _active_search_task_id = search_task_id;
+}
+
+bool SearchClientSemaphore::IsActive(int search_task_id)
+{
+    return _active_search_task_id == search_task_id;
+}
+
+void SearchClientSemaphore::CancelAll()
+{
+    _active_search_task_id = INVALID_ID;
+}
diff --git a/src/searchclients/searchclientsemaphore.h b/src/searchclients/searchclientsemaphore.h
new file mode 100644 (file)
index 0000000..5846b4f
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef SEARCHCLIENTSEMAPHORE_H
+#define SEARCHCLIENTSEMAPHORE_H
+
+#include <QMutex>
+
+class SearchClientSemaphore
+{
+public:
+    SearchClientSemaphore();
+
+    void Activate(int search_task_id);
+
+    bool IsActive(int search_task_id);
+
+    void CancelAll();
+
+private:
+    QMutex _mutex;
+    int _active_search_task_id;
+};
+
+#endif // SEARCHCLIENTSEMAPHORE_H
diff --git a/src/searchclients/theaterschedulesearchclient.cpp b/src/searchclients/theaterschedulesearchclient.cpp
new file mode 100644 (file)
index 0000000..7e1d0ce
--- /dev/null
@@ -0,0 +1,265 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "theaterschedulesearchclient.h"
+
+#include "data/cinemaschedule.h"
+#include "data/cinema.h"
+#include "data/scheduleentry.h"
+#include "data/movie.h"
+#include "utils/timeutils.h"
+#include "utils/assertedlocker.h"
+
+#include <QXmlStreamReader>
+#include <QRegExp>
+#include <iostream>
+
+TheaterScheduleSearchClient::TheaterScheduleSearchClient(CinemaSchedule *cinema_schedule, QObject *parent)
+    : AbstractSearchClient(parent),
+    _cinema_schedule(cinema_schedule)
+{
+}
+
+void TheaterScheduleSearchClient::SearchSchedule(const CinemaKey &cinema_key, const QString &url)
+{
+    setObjectName(QString("TheaterScheduleSearchClient:%1").arg(cinema_key.GetName()));
+    _semaphore.Activate(GetSearchTaskId());
+    _cinema_key = cinema_key;
+    _date = QDate::currentDate();
+    _url = QUrl::fromEncoded(QString("http://www.google.com" + url).toAscii(), QUrl::TolerantMode);
+    _dates_seen.clear();
+    _dates_seen.insert("0");
+    _date_urls.clear();
+    Search(0);
+}
+
+void TheaterScheduleSearchClient::CancelAllRunningSearchs()
+{
+    _semaphore.CancelAll();
+}
+
+void TheaterScheduleSearchClient::Search(int start)
+{
+    AbstractSearchClient::Search(_url, start);
+}
+
+void TheaterScheduleSearchClient::SearchNextDate()
+{
+    if (_date_urls.isEmpty()) {
+        return;
+    }
+    QPair<QUrl, QDate> pair = _date_urls.dequeue();
+    _date = pair.second;
+    _url = pair.first;
+    Search(0);
+}
+
+enum State {
+    PARSE_HTML,
+    PARSE_DATE_LINK,
+    PARSE_MOVIE_DIV,
+    PARSE_MOVIE_DIV1,
+    PARSE_MOVIE_LINK,
+    PARSE_MOVIE_EXPECT_DIV2,
+    PARSE_MOVIE_DIV2,
+    PARSE_MOVIE_SPAN,
+    PARSE_MOVIE_TRAILER_LINK,
+    PARSE_MOVIE_RATING,
+    PARSE_MOVIE_EXPECT_DIV3,
+    PARSE_MOVIE_DIV3,
+    PARSE_MOVIE_TIME,
+};
+
+void TheaterScheduleSearchClient::ReplyFinished(QNetworkReply *reply)
+{
+    State state = PARSE_HTML;
+    int found = 0;
+    QString movie_name;
+    QVector<QString> movie_spans;
+    QString theaters_url;
+    double rating = -1.0;
+    QList<QTime> schedule;
+    QRegExp time_pattern("\\d+:\\d+([aApP][mM])*");
+    QRegExp duration_pattern("((\\d+)hr )?(\\d+)min");
+    QRegExp reviews_pattern("\\d+ review(s)?");
+    QXmlStreamReader xml(reply);
+    while (!xml.atEnd()) {
+        QXmlStreamReader::TokenType token = xml.readNext();
+        if (token == QXmlStreamReader::StartElement) {
+            QString attr_href = xml.attributes().value("href").toString();
+            //std::cout << "name: " << qPrintable(xml.name().toString()) << ", href " << qPrintable(attr_href) << std::endl;
+            if (state == PARSE_HTML && xml.name() == "a" && attr_href.startsWith("/m/movies")) {
+                QUrl url = QUrl::fromEncoded(QString("http://www.google.com" + attr_href).toAscii(), QUrl::TolerantMode);
+                //std::cout << "LINK " << qPrintable(attr_href) << std::endl;
+                if (url.hasQueryItem("date")) {
+                    QString v = url.queryItemValue("date");
+                    //std::cout << "FOUND Date Link " << qPrintable(v) << " from " << qPrintable(url.toString()) << std::endl;
+                    if (!_dates_seen.contains(v)) {
+                        // TODO replace location with user selected location (Google simplifies to much)
+                        _dates_seen.insert(v);
+                        _date_urls.append(qMakePair(url, QDate::currentDate().addDays(v.toInt())));
+                    }
+                    state = PARSE_DATE_LINK;
+                } else if (url.hasQueryItem("mid")) {
+                    //std::cout << "FOUND Movie Link" << std::endl;
+                    movie_name = "";
+                    movie_spans.clear();
+                    theaters_url = attr_href;
+                    rating = -1.0;
+                    schedule.clear();
+                    state = PARSE_MOVIE_LINK;
+                } else {
+                    state = PARSE_HTML;
+                }
+            } else if (state == PARSE_MOVIE_EXPECT_DIV2 && xml.name() == "div") {
+                //std::cout << "PARSE_MOVIE_DIV2" << std::endl;
+                state = PARSE_MOVIE_DIV2;
+            } else if (state == PARSE_MOVIE_DIV2 && xml.name() == "span") {
+                movie_spans.append("");
+                //std::cout << "PARSE_MOVIE_SPAN" << std::endl;
+                state = PARSE_MOVIE_SPAN;
+            } else if (state == PARSE_MOVIE_DIV2 && xml.name() == "a") {
+                state = PARSE_MOVIE_TRAILER_LINK;
+            } else if (state == PARSE_MOVIE_DIV2 && xml.name() == "img") {
+                rating = (double) xml.attributes().value("src").at(41).digitValue() / 10.0;
+                //std::cout << "rate: " << rate << std::endl;
+                state = PARSE_MOVIE_RATING;
+            } else if (state == PARSE_MOVIE_EXPECT_DIV3 && xml.name() == "div") {
+                //std::cout << "PARSE_MOVIE_DIV3" << std::endl;
+                state = PARSE_MOVIE_DIV3;
+            } else if (state == PARSE_MOVIE_DIV3 && xml.name() == "span") {
+                //std::cout << "PARSE_MOVIE_TIME" << std::endl;
+                state = PARSE_MOVIE_TIME;
+            } else {
+                //std::cout << "TAG " << qPrintable(xml.name().toString()) << std::endl;
+                state = PARSE_HTML;
+            }
+        } else if (token == QXmlStreamReader::EndElement) {
+            if (state == PARSE_DATE_LINK) {
+                state = PARSE_HTML;
+            } else if (state == PARSE_MOVIE_LINK) {
+                state = PARSE_MOVIE_DIV1;
+            } else if (state == PARSE_MOVIE_DIV1) {
+                state = PARSE_MOVIE_EXPECT_DIV2;
+            } else if (state == PARSE_MOVIE_SPAN) {
+                state = PARSE_MOVIE_DIV2;
+            } else if (state == PARSE_MOVIE_TRAILER_LINK) {
+                state = PARSE_MOVIE_DIV2;
+            } else if (state == PARSE_MOVIE_RATING) {
+                state = PARSE_MOVIE_DIV2;
+            } else if (state == PARSE_MOVIE_DIV2) {
+                state = PARSE_MOVIE_EXPECT_DIV3;
+            } else if (state == PARSE_MOVIE_TIME) {
+                state = PARSE_MOVIE_DIV3;
+            } else if (state == PARSE_MOVIE_DIV3) {
+                state = PARSE_MOVIE_DIV;
+            } else if (state == PARSE_MOVIE_DIV) {
+                if (!movie_name.isEmpty()) {
+                    ++found;
+                    if (!schedule.isEmpty()) {
+                        AssertedWriteLocker locker(_cinema_schedule->GetLock());
+                        if (!_semaphore.IsActive(GetSearchTaskId())) {
+                            break;
+                        }
+                        const Cinema *cinema = _cinema_schedule->FindCinema(_cinema_key);
+                        if (cinema != 0) {
+                            //std::cout << "ADD SCHEDULE " << qPrintable(movie_name) << ", " << qPrintable(duration)
+                            //        << ", " << qPrintable(age) << ", " << rate << std::endl;
+                            MovieKey key(movie_name);
+                            Movie *movie = _cinema_schedule->FindMovie(key);
+                            if (movie == 0) {
+                                movie = _cinema_schedule->AddMovie(key);
+                            }
+                            if (!theaters_url.isEmpty()) {
+                                movie->SetTheatersUrl(theaters_url);
+                            }
+                            if (rating >= 0.0) {
+                                movie->SetRate(rating);
+                            }
+                            Q_FOREACH (QString s, movie_spans) {
+                                if (duration_pattern.exactMatch(s)) {
+                                    QString hours = duration_pattern.cap(2);
+                                    QString minutes = duration_pattern.cap(3);
+                                    //std::cout << "hours = " << qPrintable(hours) << ", minutes = " << qPrintable(minutes) << ",0: " << qPrintable(duration_pattern.cap(0)) << ", 1: " << qPrintable(duration_pattern.cap(1)) << std::endl;
+                                    movie->SetDuration(QTime(hours.toInt(), minutes.toInt()));
+                                } else if (reviews_pattern.exactMatch(s)) {
+                                    // Ignore number of reviews
+                                } else {
+                                    movie->SetComment(s);
+                                }
+                            }
+                            Q_FOREACH(const QTime time, schedule) {
+                                _cinema_schedule->AddSchedule(cinema, movie, time, _date);
+                            }
+                        }
+                    }
+                }
+                state = PARSE_HTML;
+            }
+        } else if (token == QXmlStreamReader::Characters) {
+            if (state == PARSE_MOVIE_LINK) {
+                //std::cout << "MOVIE " << qPrintable(xml.text().toString()) << std::endl;
+                movie_name = xml.text().toString();
+            } else if (state == PARSE_MOVIE_SPAN) {
+                int i = movie_spans.size()-1;
+                if (movie_spans[i].isEmpty()) {
+                    movie_spans[i] = xml.text().toString();
+                } else if (!xml.text().isEmpty()) {
+                    movie_spans[i] += " ";
+                    movie_spans[i] += xml.text().toString();
+                }
+                //std::cout << " span: " << qPrintable(movie_spans[i]) << std::endl;
+            } else if (state == PARSE_MOVIE_TIME) {
+                QString t = xml.text().toString();
+                int i = 0;
+                while ((i = time_pattern.indexIn(t, i)) != -1) {
+                    int length = time_pattern.matchedLength();
+                    QTime time = TimeUtils::FromTimeString(t.mid(i, length));
+                    if (time.isValid()) {
+                        schedule.append(time);
+                    } else {
+                        //std::cout << "ERROR: time " << qPrintable(t.mid(i, length)) << " is invalid." << std::endl;
+                    }
+                    i += length;
+                }
+            }
+        }
+    }
+    if (xml.hasError()) {
+        emit SearchFinished(GetSearchTaskId(), false);
+        std::cout << "xml error (" << xml.lineNumber() << "/" << xml.columnNumber() << "): " << qPrintable(xml.errorString()) << std::endl;
+        emit Error(GetSearchTaskId());
+        deleteLater();
+    } else if (!_semaphore.IsActive(GetSearchTaskId())) {
+        emit Cancelled(GetSearchTaskId());
+        emit SearchFinished(GetSearchTaskId(), false);
+    } else {
+        // all movies are listed on one page
+        // no repetition of search with start parameter
+        if (!_date_urls.isEmpty()) {
+            emit Reply(GetSearchTaskId(), true);
+            SearchNextDate();
+        } else {
+            emit Reply(GetSearchTaskId(), false);
+            emit SearchFinished(GetSearchTaskId(), true);
+            deleteLater();
+        }
+    }
+    reply->deleteLater();
+}
+
+SearchClientSemaphore TheaterScheduleSearchClient::_semaphore;
diff --git a/src/searchclients/theaterschedulesearchclient.h b/src/searchclients/theaterschedulesearchclient.h
new file mode 100644 (file)
index 0000000..0556ec2
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef THEATERSCHEDULESEARCHCLIENT_H
+#define THEATERSCHEDULESEARCHCLIENT_H
+
+#include "abstractsearchclient.h"
+#include "searchclientsemaphore.h"
+#include "data/cinemakey.h"
+
+#include <QDate>
+#include <QUrl>
+#include <QSet>
+#include <QQueue>
+#include <QPair>
+
+class CinemaSchedule;
+
+class TheaterScheduleSearchClient : public AbstractSearchClient
+{
+    Q_OBJECT
+public:
+    explicit TheaterScheduleSearchClient(CinemaSchedule *cinema_schedule, QObject *parent = 0);
+
+    void SearchSchedule(const CinemaKey &cinema_key, const QString &url);
+
+    static void CancelAllRunningSearchs();
+
+private:
+    void Search(int start);
+    void SearchNextDate();
+    Q_SLOT virtual void ReplyFinished(QNetworkReply *);
+
+private:
+    CinemaSchedule *_cinema_schedule;
+    CinemaKey _cinema_key;
+    QDate _date;
+    QUrl _url;
+    QSet<QString> _dates_seen;
+    QQueue<QPair<QUrl, QDate> > _date_urls;
+    static SearchClientSemaphore _semaphore;
+};
+
+#endif // THEATERSCHEDULESEARCHCLIENT_H
diff --git a/src/searchclients/theatersearchclient.cpp b/src/searchclients/theatersearchclient.cpp
new file mode 100644 (file)
index 0000000..f4f02dc
--- /dev/null
@@ -0,0 +1,163 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "theatersearchclient.h"
+
+#include "data/cinemakey.h"
+#include "data/cinema.h"
+#include "data/cinemaschedule.h"
+#include "utils/assertedlocker.h"
+
+#include <QXmlStreamReader>
+#include <iostream>
+
+TheaterSearchClient::TheaterSearchClient(CinemaSchedule *cinema_schedule, QObject *parent)
+    : AbstractSearchClient(parent),
+    _cinema_schedule(cinema_schedule)
+{
+}
+
+void TheaterSearchClient::SearchTheater(const QString &town)
+{
+    _semaphore.Activate(GetSearchTaskId());
+    setObjectName(QString("TheaterSearchClient:%1").arg(town));
+    _town = town;
+    Search(0);
+}
+
+void TheaterSearchClient::CancelAllRunningSearchs()
+{
+    _semaphore.CancelAll();
+}
+
+void TheaterSearchClient::Search(int start)
+{
+    QUrl url("http://www.google.com/m/movies");
+    url.addQueryItem("loc", _town);
+    url.addQueryItem("sort", QString::number(0));
+    AbstractSearchClient::Search(url, start);
+}
+
+enum State {
+    PARSE_HTML,
+    PARSE_THEATER_LINK,
+    PARSE_THEATER_DIV,
+    PARSE_THEATER_BR,
+    PARSE_THEATER_SPAN,
+    PARSE_THEATER_PHONE
+};
+
+void TheaterSearchClient::ReplyFinished(QNetworkReply *reply)
+{
+    QXmlStreamReader xml(reply);
+    State state = PARSE_HTML;
+    int found = 0;
+    QString theater_name;
+    QString theater_address;
+    QString theater_movies_url;
+    QString theater_phone;
+    while (!xml.atEnd()) {
+        QXmlStreamReader::TokenType token = xml.readNext();
+        if (token == QXmlStreamReader::StartElement) {
+            QString attr_href = xml.attributes().value("href").toString();
+            //std::cout << "name: " << qPrintable(xml.name().toString()) << ", href: " << qPrintable(attr_href) << std::endl;
+            if (state == PARSE_HTML && xml.name() == "a" && attr_href.startsWith("/m/movies")) {
+                QUrl url = QUrl::fromEncoded(QString("http://www.google.com" + attr_href).toAscii(), QUrl::TolerantMode);
+                //std::cout << "LINK " << qPrintable(attr_href) << std::endl;
+                if (url.hasQueryItem("tid")) {
+                    theater_name = "";
+                    theater_address = "";
+                    theater_movies_url = attr_href;
+                    theater_phone = "";
+                    state = PARSE_THEATER_LINK;
+                } else {
+                    state = PARSE_HTML;
+                }
+            } else if (state == PARSE_THEATER_DIV && xml.name() == "br") {
+                state = PARSE_THEATER_BR;
+            } else if (state == PARSE_THEATER_DIV && xml.name() == "span") {
+                state = PARSE_THEATER_SPAN;
+            } else if (state == PARSE_THEATER_DIV && xml.name() == "a" && attr_href.startsWith("wtai:")) {
+                state = PARSE_THEATER_PHONE;
+            } else if (state == PARSE_THEATER_DIV && xml.name() == "a") {
+                state = PARSE_THEATER_BR;
+            } else {
+                state = PARSE_HTML;
+            }
+        } else if (token == QXmlStreamReader::EndElement) {
+            if (state == PARSE_THEATER_LINK) {
+                state = PARSE_THEATER_DIV;
+            } else if (state == PARSE_THEATER_BR) {
+                state = PARSE_THEATER_DIV;
+            } else if (state == PARSE_THEATER_SPAN) {
+                state = PARSE_THEATER_DIV;
+            } else if (state == PARSE_THEATER_PHONE) {
+                state = PARSE_THEATER_DIV;
+            } else if (state == PARSE_THEATER_DIV) {
+                if (!theater_name.isEmpty()) {
+                    AssertedWriteLocker locker(_cinema_schedule->GetLock());
+                    if (!_semaphore.IsActive(GetSearchTaskId())) {
+                        break;
+                    }
+                    ++found;
+                    CinemaKey key(theater_name, theater_address);
+                    Cinema *cinema = _cinema_schedule->FindCinema(key);
+                    if (cinema == 0) {
+                        cinema = _cinema_schedule->AddCinema(key);
+                    }
+                    if (!theater_movies_url.isEmpty()) {
+                        cinema->SetMoviesUrl(theater_movies_url);
+                    }
+                    if (!theater_phone.isEmpty()) {
+                        cinema->SetTelephone(theater_phone);
+                    }
+                }
+                state = PARSE_HTML;
+            }
+        } else if (token == QXmlStreamReader::Characters) {
+            if (state == PARSE_THEATER_LINK) {
+                theater_name = xml.text().toString();
+            } else if (state == PARSE_THEATER_PHONE) {
+                theater_phone = xml.text().toString();
+            } else if (state == PARSE_THEATER_SPAN) {
+                theater_address = xml.text().toString();
+            }
+        }
+    }
+    if (xml.hasError()) {
+        emit SearchFinished(GetSearchTaskId(), false);
+        std::cout << "xml error (" << xml.lineNumber() << "/" << xml.columnNumber() << "): " << qPrintable(xml.errorString()) << std::endl;
+        emit Error(GetSearchTaskId());
+        deleteLater();
+    } else if (!_semaphore.IsActive(GetSearchTaskId())) {
+        emit Cancelled(GetSearchTaskId());
+        emit SearchFinished(GetSearchTaskId(), false);
+        deleteLater();
+    } else {
+        if (found > 0) {
+            emit Reply(GetSearchTaskId(), true);
+            Search(GetStartIndex() + found);
+        } else {
+            emit Reply(GetSearchTaskId(), false);
+            emit SearchFinished(GetSearchTaskId(), true);
+            deleteLater();
+        }
+    }
+    reply->deleteLater();
+}
+
+SearchClientSemaphore TheaterSearchClient::_semaphore;
diff --git a/src/searchclients/theatersearchclient.h b/src/searchclients/theatersearchclient.h
new file mode 100644 (file)
index 0000000..d1c76bf
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef THEATERSEARCHCLIENT_H
+#define THEATERSEARCHCLIENT_H
+
+#include "abstractsearchclient.h"
+#include "searchclientsemaphore.h"
+
+class CinemaSchedule;
+
+class TheaterSearchClient : public AbstractSearchClient
+{
+    Q_OBJECT
+public:
+    explicit TheaterSearchClient(CinemaSchedule *cinema_schedule, QObject *parent = 0);
+
+    void SearchTheater(const QString &town);
+
+    static void CancelAllRunningSearchs();
+
+private:
+    void Search(int start);
+    Q_SLOT virtual void ReplyFinished(QNetworkReply *);
+
+private:
+    CinemaSchedule *_cinema_schedule;
+    QString _town;
+    static SearchClientSemaphore _semaphore;
+};
+
+#endif // THEATERSEARCHCLIENT_H
diff --git a/src/src.pro b/src/src.pro
new file mode 100644 (file)
index 0000000..eb34058
--- /dev/null
@@ -0,0 +1,228 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2010-03-01T19:21:07
+#
+#-------------------------------------------------
+
+QT       += core gui network dbus
+
+CONFIG += link_pkgconfig
+
+maemo5 {
+    QT += maemo5
+    DEFINES += Q_WS_MAEMO_5
+    maemo_sdk {
+        CONFIG += icd2
+        PKGCONFIG += calendar-backend liblocation
+        DEFINES += MAEMO_SDK LIBLOCATION
+    }
+}
+
+mobility {
+    MOBILITY += location
+    DEFINES += QT_MOBILITY
+    !contains(DEFINES, LIBLOCATION) {
+        DEFINES += QT_MOBILITY_LOCATION
+    }
+}
+
+TARGET = movie-schedule
+TEMPLATE = app
+
+INCLUDEPATH += .
+
+SOURCES += \
+    main.cpp \
+    control/actioncontroller.cpp \
+    control/maincontroller.cpp \
+    control/moviecontroller.cpp \
+    control/settingscontroller.cpp \
+    control/theatercontroller.cpp \
+    data/cinema.cpp \
+    data/cinemakey.cpp \
+    data/cinemaschedule.cpp \
+    data/location.cpp \
+    data/movie.cpp \
+    data/moviekey.cpp \
+    data/scheduleentry.cpp \
+    data/scheduleentrykey.cpp \
+    data/settings.cpp \
+    searchclients/abstractsearchclient.cpp \
+    searchclients/movieschedulesearchclient.cpp \
+    searchclients/moviesearchclient.cpp \
+    searchclients/theaterschedulesearchclient.cpp \
+    searchclients/theatersearchclient.cpp \
+    ui/abstractmainwindow.cpp \
+    ui/backgroundlabel.cpp \
+    ui/cinemapainter.cpp \
+    ui/contextdialog.cpp \
+    ui/daypainter.cpp \
+    ui/locationdialog.cpp \
+    ui/mainwindow.cpp \
+    ui/moviedelegate.cpp \
+    ui/moviemodel.cpp \
+    ui/moviepainter.cpp \
+    ui/moviescheduledelegate.cpp \
+    ui/movieschedulemodel.cpp \
+    ui/moviewindow.cpp \
+    ui/ratingprovider.cpp \
+    ui/theaterdelegate.cpp \
+    ui/theatermodel.cpp \
+    ui/theaterscheduledelegate.cpp \
+    ui/theaterschedulemodel.cpp \
+    ui/theaterwindow.cpp \
+    ui/uiutils.cpp \
+    utils/assertedlock.cpp \
+    utils/assertedlocker.cpp \
+    utils/calendar.cpp \
+    utils/timeutils.cpp \
+    movieschedule.cpp \
+    ui/scheduleentryitem.cpp \
+    control/itemmodelsortcontroller.cpp \
+    control/itemmodelsortclient.cpp \
+    control/itemmodelsortproxy.cpp \
+    utils/asynccallclient.cpp \
+    utils/asynccallproxy.cpp \
+    utils/asynccall.cpp \
+    ui/styleutils.cpp \
+    searchclients/gpsclient.cpp \
+    ui/aboutdialog.cpp \
+    searchclients/searchclientsemaphore.cpp \
+    control/locationcontroller.cpp \
+    utils/connectivitymanager.cpp
+
+HEADERS  += \
+    control/actioncontroller.h \
+    control/maincontroller.h \
+    control/moviecontroller.h \
+    control/settingscontroller.h \
+    control/theatercontroller.h \
+    data/cinema.h \
+    data/cinemakey.h \
+    data/cinemaschedule.h \
+    data/location.h \
+    data/movie.h \
+    data/moviekey.h \
+    data/scheduleentry.h \
+    data/scheduleentrykey.h \
+    data/settings.h \
+    searchclients/abstractsearchclient.h \
+    searchclients/movieschedulesearchclient.h \
+    searchclients/moviesearchclient.h \
+    searchclients/theaterschedulesearchclient.h \
+    searchclients/theatersearchclient.h \
+    ui/abstractmainwindow.h \
+    ui/backgroundlabel.h \
+    ui/cinemapainter.h \
+    ui/contextdialog.h \
+    ui/daypainter.h \
+    ui/locationdialog.h \
+    ui/mainwindow.h \
+    ui/moviedelegate.h \
+    ui/moviemodel.h \
+    ui/moviepainter.h \
+    ui/moviescheduledelegate.h \
+    ui/movieschedulemodel.h \
+    ui/moviewindow.h \
+    ui/ratingprovider.h \
+    ui/theaterdelegate.h \
+    ui/theatermodel.h \
+    ui/theaterscheduledelegate.h \
+    ui/theaterschedulemodel.h \
+    ui/theaterwindow.h \
+    ui/uiutils.h \
+    utils/assertedlock.h \
+    utils/assertedlocker.h \
+    utils/calendar.h \
+    utils/timeutils.h \
+    utils/connect.h \
+    movieschedule.h \
+    ui/scheduleentryitem.h \
+    control/itemmodelsortcontroller.h \
+    control/itemmodelsortclient.h \
+    control/itemmodelsortproxy.h \
+    utils/asynccallclient.h \
+    utils/asynccallproxy.h \
+    utils/asynccall.h \
+    ui/styleutils.h \
+    searchclients/gpsclient.h \
+    ui/aboutdialog.h \
+    searchclients/searchclientsemaphore.h \
+    control/locationcontroller.h \
+    utils/connectivitymanager.h
+
+FORMS    += \
+    ui/theaterwindow.ui \
+    ui/mainwindow.ui \
+    ui/locationdialog.ui \
+    ui/moviewindow.ui \
+    ui/contextdialog.ui \
+    ui/aboutdialog.ui
+
+RESOURCES += \
+    resources.qrc
+
+TRANSLATIONS += \
+    translations/movie-schedule_de.ts
+
+OTHER_FILES += \
+    translations/movie-schedule_de.ts \
+    ../data/movie-schedule.desktop \
+    ../debian/copyright \
+    ../debian/control \
+    ../debian/changelog \
+    ../debian/rules \
+    ../data/clap.xcf \
+    ../README \
+    (Example) \
+    ../COPYING \
+    ../debian/postinst \
+    ../debian/optify \
+    ../debian/compat
+
+!isEmpty(TRANSLATIONS) {
+    isEmpty(QMAKE_LRELEASE) {
+        win32:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]\lrelease.exe
+        else:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease
+    }
+
+    isEmpty(TS_DIR):TS_DIR = translations
+
+    TSQM.name = lrelease ${QMAKE_FILE_IN}
+    TSQM.input = TRANSLATIONS
+    TSQM.output = $$TS_DIR/${QMAKE_FILE_BASE}.qm
+    TSQM.commands = $$QMAKE_LRELEASE ${QMAKE_FILE_IN} -qm $$TS_DIR/${QMAKE_FILE_BASE}.qm
+    TSQM.CONFIG = no_link
+    QMAKE_EXTRA_COMPILERS += TSQM
+
+    PRE_TARGETDEPS += compiler_TSQM_make_all
+}
+
+unix {
+    #VARIABLES
+    isEmpty(PREFIX) {
+        PREFIX = /usr/local
+        DEFINES += DEFAULT_PREFIX
+    }
+
+    BINDIR = $$PREFIX/bin
+    DATADIR =$$PREFIX/share
+
+    DEFINES += DATADIR=\"$$DATADIR\" PKGDATADIR=\"$$PKGDATADIR\"
+
+    #MAKE INSTALL
+
+    INSTALLS += target desktop scalable i18n
+
+    target.path = $$BINDIR
+
+    desktop.path = $$DATADIR/applications/hildon
+    desktop.files += ../data/$${TARGET}.desktop
+
+    scalable.path = $$DATADIR/icons/hicolor/scalable/hildon
+    scalable.files += ../data/scalable/$${TARGET}.png
+
+    i18n.path = $$DATADIR/$${TARGET}
+    i18n.files += ../builddir/src/translations
+
+}
diff --git a/src/translations/movie-schedule_de.ts b/src/translations/movie-schedule_de.ts
new file mode 100644 (file)
index 0000000..234d259
--- /dev/null
@@ -0,0 +1,319 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="de_DE">
+<context>
+    <name>AboutDialog</name>
+    <message>
+        <location filename="../ui/aboutdialog.ui" line="14"/>
+        <source>About</source>
+        <translation>Über</translation>
+    </message>
+    <message>
+        <location filename="../ui/aboutdialog.ui" line="28"/>
+        <source>MovieSchedule</source>
+        <translation>MovieSchedule</translation>
+    </message>
+    <message utf8="true">
+        <location filename="../ui/aboutdialog.ui" line="109"/>
+        <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Sans&apos;; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt;This software is ©2010 Jochen Becher.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:18pt;&quot;&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt;Movies, Theaters, Schedules and GPS Locations use &lt;/span&gt;&lt;a href=&quot;http://www.google.com&quot;&gt;&lt;span style=&quot; font-size:18pt; font-weight:600; text-decoration: underline; color:#2eacff;&quot;&gt;Google&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt; services.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:18pt;&quot;&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:14pt;&quot;&gt;This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Sans&apos;; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt;Diese Software ist ©2010 Jochen Becher.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:18pt;&quot;&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt;Filme, Kinos, Startzeiten und GPS Orte benutzen &lt;/span&gt;&lt;a href=&quot;http://www.google.com&quot;&gt;&lt;span style=&quot; font-size:18pt; font-weight:600; text-decoration: underline; color:#2eacff;&quot;&gt;Google&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt; Dienste.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:18pt;&quot;&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:14pt;&quot;&gt;Dieses Programm ist freie Software. Sie können es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation veröffentlicht, weitergeben und/oder modifizieren, entweder gemäß Version 3 der Lizenz oder (nach Ihrer Option) jeder späteren Version.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message utf8="true">
+        <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Sans&apos;; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;This software is ©2010 Jochen Becher.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:16pt;&quot;&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;Movies, Theaters, Schedules and GPS Locations use &lt;/span&gt;&lt;a href=&quot;http://www.google.com&quot;&gt;&lt;span style=&quot; font-size:16pt; text-decoration: underline; color:#0000ff;&quot;&gt;Google &lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;services.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:16pt;&quot;&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+        <translation type="obsolete">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Sans&apos;; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;Diese Software ist ©2010 Jochen Becher.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:16pt;&quot;&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;Filme, Kinos, Startzeiten and GPS Orte benutzen &lt;/span&gt;&lt;a href=&quot;http://www.google.com&quot;&gt;&lt;span style=&quot; font-size:16pt; text-decoration: underline; color:#0000ff;&quot;&gt;Google &lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;Dienste.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:16pt;&quot;&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Dieses Programm ist freie Software. Sie können es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation veröffentlicht, weitergeben und/oder modifizieren, entweder gemäß Version 3 der Lizenz oder (nach Ihrer Option) jeder späteren Version.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+    </message>
+    <message>
+        <location filename="../ui/aboutdialog.ui" line="143"/>
+        <source>Contact</source>
+        <translation>Kontakt</translation>
+    </message>
+    <message>
+        <location filename="../ui/aboutdialog.ui" line="153"/>
+        <source>Done</source>
+        <translation>Fertig</translation>
+    </message>
+</context>
+<context>
+    <name>ActionController</name>
+    <message>
+        <location filename="../control/actioncontroller.cpp" line="79"/>
+        <location filename="../control/actioncontroller.cpp" line="88"/>
+        <location filename="../control/actioncontroller.cpp" line="92"/>
+        <source>Adding calendar event failed.</source>
+        <translation>Hinzufügen des Kalendereintrags fehlgeschlagen.</translation>
+    </message>
+    <message>
+        <location filename="../control/actioncontroller.cpp" line="83"/>
+        <source>%1 (%2 %3) added to your calendar.</source>
+        <translation>%1 (%2, %3) zum Kalender hinzugefügt.</translation>
+    </message>
+    <message>
+        <location filename="../control/actioncontroller.cpp" line="109"/>
+        <source>Unable to call theater by phone: communication bus not available.</source>
+        <translation>Telefonanruf fehlgeschlagen: Keine Kommunikation mit dem Telefon möglich.</translation>
+    </message>
+    <message>
+        <location filename="../control/actioncontroller.cpp" line="114"/>
+        <source>Unable to call theater by phone: phone service not available.</source>
+        <translation>Telefonanruf fehlgeschlagen: Telefonfunktion steht nicht zur Verfügung.</translation>
+    </message>
+    <message>
+        <location filename="../control/actioncontroller.cpp" line="121"/>
+        <source>Unable to call theater by phone: call failed.</source>
+        <translation>Telefonanruf fehlgeschlagen: Kein Anruf möglich.</translation>
+    </message>
+    <message>
+        <location filename="../control/actioncontroller.cpp" line="221"/>
+        <source>Unable to search in web: communication bus not available.</source>
+        <translation>Websuche fehlgeschlagen: Kommunikation mit Browser nicht möglich.</translation>
+    </message>
+    <message>
+        <location filename="../control/actioncontroller.cpp" line="226"/>
+        <location filename="../control/actioncontroller.cpp" line="232"/>
+        <source>Unable to search in web: browser service not available.</source>
+        <translation>Websuche fehlgeschlagen: Browser steht nicht zur Verfügung.</translation>
+    </message>
+</context>
+<context>
+    <name>ContextDialog</name>
+    <message>
+        <location filename="../ui/contextdialog.ui" line="14"/>
+        <source>Actions</source>
+        <translation>Aktionen</translation>
+    </message>
+    <message>
+        <location filename="../ui/contextdialog.ui" line="35"/>
+        <source>Add to Calendar</source>
+        <translation>Im Kalender eintragen</translation>
+    </message>
+    <message>
+        <location filename="../ui/contextdialog.ui" line="42"/>
+        <source>Call Theater By Phone</source>
+        <translation>Kino anrufen</translation>
+    </message>
+    <message>
+        <location filename="../ui/contextdialog.ui" line="49"/>
+        <source>Find Route to Theater</source>
+        <translation>Weg zum Kino suchen</translation>
+    </message>
+    <message>
+        <location filename="../ui/contextdialog.ui" line="56"/>
+        <source>Search Movie in Web</source>
+        <translation>Film im Web suchen</translation>
+    </message>
+    <message>
+        <location filename="../ui/contextdialog.ui" line="63"/>
+        <source>Search Theater in Web</source>
+        <translation>Kino im Web suchen</translation>
+    </message>
+</context>
+<context>
+    <name>LocationController</name>
+    <message>
+        <location filename="../control/locationcontroller.cpp" line="25"/>
+        <source>Unable to detect current city.</source>
+        <translation>Die nächste Stadt wurde nicht gefunden.</translation>
+    </message>
+</context>
+<context>
+    <name>LocationDialog</name>
+    <message>
+        <location filename="../ui/locationdialog.ui" line="20"/>
+        <source>Location</source>
+        <translation>Ort</translation>
+    </message>
+    <message>
+        <location filename="../ui/locationdialog.ui" line="49"/>
+        <source>Search Near</source>
+        <translation>In der Nähe suchen</translation>
+    </message>
+    <message>
+        <location filename="../ui/locationdialog.ui" line="116"/>
+        <source>City</source>
+        <translation>Stadt</translation>
+    </message>
+    <message>
+        <location filename="../ui/locationdialog.ui" line="149"/>
+        <source>Search</source>
+        <translation>Suchen</translation>
+    </message>
+</context>
+<context>
+    <name>MainController</name>
+    <message>
+        <source>Unable to access network</source>
+        <translation type="obsolete">Netzwerk steht nicht zur Verfügung.</translation>
+    </message>
+    <message>
+        <location filename="../control/maincontroller.cpp" line="43"/>
+        <source>Unable to access network.</source>
+        <translation>Netzwerk steht nicht zur Verfügung.</translation>
+    </message>
+    <message>
+        <location filename="../control/maincontroller.cpp" line="44"/>
+        <source>No theaters found near %1.</source>
+        <translation>Keine Kinos in der Nähe von %1 gefunden.</translation>
+    </message>
+    <message>
+        <location filename="../control/maincontroller.cpp" line="45"/>
+        <source>No movies found near %1.</source>
+        <translation>Keine Filme in der Nähe von %1 gefunden.</translation>
+    </message>
+    <message>
+        <location filename="../control/maincontroller.cpp" line="46"/>
+        <source>Error on fetching theaters.</source>
+        <translation>Fehler beim Lesen der Kinoliste.</translation>
+    </message>
+    <message>
+        <location filename="../control/maincontroller.cpp" line="47"/>
+        <source>Error on fetching movies.</source>
+        <translation>Fehler beim Lesen der Filmliste.</translation>
+    </message>
+</context>
+<context>
+    <name>MainWindow</name>
+    <message>
+        <location filename="../ui/mainwindow.cpp" line="75"/>
+        <location filename="../ui/mainwindow.cpp" line="113"/>
+        <source>Movies</source>
+        <translation>Filme</translation>
+    </message>
+    <message>
+        <location filename="../ui/mainwindow.cpp" line="76"/>
+        <location filename="../ui/mainwindow.cpp" line="105"/>
+        <source>Theaters</source>
+        <translation>Kinos</translation>
+    </message>
+    <message>
+        <location filename="../ui/mainwindow.cpp" line="77"/>
+        <source>Location</source>
+        <translation>Ort</translation>
+    </message>
+    <message>
+        <location filename="../ui/mainwindow.cpp" line="78"/>
+        <source>About</source>
+        <translation>Über</translation>
+    </message>
+    <message>
+        <location filename="../ui/mainwindow.cpp" line="80"/>
+        <source>Call By Phone</source>
+        <translation>Kino anrufen</translation>
+    </message>
+    <message>
+        <location filename="../ui/mainwindow.cpp" line="81"/>
+        <source>Find Route</source>
+        <translation>Weg zum Kino suchen</translation>
+    </message>
+    <message>
+        <location filename="../ui/mainwindow.cpp" line="82"/>
+        <location filename="../ui/mainwindow.cpp" line="84"/>
+        <source>Search In Web</source>
+        <translation>Im Web suchen</translation>
+    </message>
+    <message>
+        <source>Movie-Schedule</source>
+        <translation type="obsolete">Kinoprogramm</translation>
+    </message>
+    <message>
+        <location filename="../ui/mainwindow.ui" line="14"/>
+        <location filename="../ui/mainwindow.cpp" line="120"/>
+        <source>MovieSchedule</source>
+        <translation>MovieSchedule</translation>
+    </message>
+</context>
+<context>
+    <name>MovieController</name>
+    <message>
+        <location filename="../control/moviecontroller.cpp" line="35"/>
+        <source>No schedule found for %1.</source>
+        <translation>Kein Kinoprogramm für %1 gefunden.</translation>
+    </message>
+    <message>
+        <location filename="../control/moviecontroller.cpp" line="36"/>
+        <source>Error on fetching movie schedule.</source>
+        <translation>Fehler beim Lesen des Kinoprogramms.</translation>
+    </message>
+</context>
+<context>
+    <name>MovieWindow</name>
+    <message>
+        <location filename="../ui/moviewindow.ui" line="14"/>
+        <source>Movie</source>
+        <translation>Film</translation>
+    </message>
+</context>
+<context>
+    <name>QObject</name>
+    <message>
+        <location filename="../utils/timeutils.cpp" line="79"/>
+        <source>Today</source>
+        <comment>DayPainter</comment>
+        <translation>Heute</translation>
+    </message>
+    <message>
+        <location filename="../utils/timeutils.cpp" line="81"/>
+        <source>Tomorrow</source>
+        <comment>DayPainter</comment>
+        <translation>Morgen</translation>
+    </message>
+    <message>
+        <location filename="../ui/moviepainter.cpp" line="52"/>
+        <source>%1min</source>
+        <comment>movie duration</comment>
+        <translation>%1Min</translation>
+    </message>
+</context>
+<context>
+    <name>TheaterController</name>
+    <message>
+        <location filename="../control/theatercontroller.cpp" line="35"/>
+        <source>No schedule found for %1.</source>
+        <translation>Kein Kinoprogramm für %1 gefunden.</translation>
+    </message>
+    <message>
+        <location filename="../control/theatercontroller.cpp" line="36"/>
+        <source>Error on fetching theater schedule.</source>
+        <translation>Fehler beim Lesen des Kinoprogramms.</translation>
+    </message>
+</context>
+<context>
+    <name>TheaterWindow</name>
+    <message>
+        <location filename="../ui/theaterwindow.ui" line="14"/>
+        <source>Theater</source>
+        <translation>Kino</translation>
+    </message>
+</context>
+</TS>
diff --git a/src/ui/aboutdialog.cpp b/src/ui/aboutdialog.cpp
new file mode 100644 (file)
index 0000000..63e5d6c
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "aboutdialog.h"
+#include "ui_aboutdialog.h"
+
+AboutDialog::AboutDialog(QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::AboutDialog)
+{
+    ui->setupUi(this);
+    ui->_button_box->addButton(ui->_done_button, QDialogButtonBox::AcceptRole);
+    ui->_button_box->addButton(ui->_contact_button, QDialogButtonBox::ActionRole);
+    //QPalette palette = ui->_about_text->palette();
+    //palette.setColor(QPalette::Base, palette.color(QPalette::Window));
+    //palette.setColor(QPalette::Text, palette.color(QPalette::WindowText));
+    //ui->_about_text->setPalette(palette);
+    connect(ui->_button_box, SIGNAL(accepted()), this, SLOT(deleteLater()));
+    connect(ui->_button_box, SIGNAL(rejected()), this, SLOT(deleteLater()));
+    connect(ui->_contact_button, SIGNAL(clicked()), this, SLOT(deleteLater()));
+    connect(ui->_contact_button, SIGNAL(clicked()), this, SIGNAL(ContactAuthor()));
+}
+
+AboutDialog::~AboutDialog()
+{
+    delete ui;
+}
diff --git a/src/ui/aboutdialog.h b/src/ui/aboutdialog.h
new file mode 100644 (file)
index 0000000..0ea60e9
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef ABOUTDIALOG_H
+#define ABOUTDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+    class AboutDialog;
+}
+
+class AboutDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit AboutDialog(QWidget *parent = 0);
+    ~AboutDialog();
+
+public:
+    Q_SIGNAL void ContactAuthor();
+
+private:
+    Ui::AboutDialog *ui;
+};
+
+#endif // ABOUTDIALOG_H
diff --git a/src/ui/aboutdialog.ui b/src/ui/aboutdialog.ui
new file mode 100644 (file)
index 0000000..c3e37f2
--- /dev/null
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AboutDialog</class>
+ <widget class="QDialog" name="AboutDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>443</width>
+    <height>233</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>About</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0" colspan="2">
+    <widget class="QLabel" name="_title">
+     <property name="font">
+      <font>
+       <family>Sans Serif</family>
+       <pointsize>22</pointsize>
+       <weight>75</weight>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="text">
+      <string>MovieSchedule</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="1" rowspan="4">
+    <widget class="QDialogButtonBox" name="_button_box">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel</set>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0" rowspan="6">
+    <widget class="QScrollArea" name="scrollArea">
+     <property name="horizontalScrollBarPolicy">
+      <enum>Qt::ScrollBarAlwaysOff</enum>
+     </property>
+     <property name="widgetResizable">
+      <bool>true</bool>
+     </property>
+     <widget class="QWidget" name="scrollAreaWidgetContents">
+      <property name="geometry">
+       <rect>
+        <x>0</x>
+        <y>0</y>
+        <width>311</width>
+        <height>434</height>
+       </rect>
+      </property>
+      <property name="palette">
+       <palette>
+        <active>
+         <colorrole role="Base">
+          <brush brushstyle="SolidPattern">
+           <color alpha="255">
+            <red>255</red>
+            <green>0</green>
+            <blue>0</blue>
+           </color>
+          </brush>
+         </colorrole>
+        </active>
+        <inactive>
+         <colorrole role="Base">
+          <brush brushstyle="SolidPattern">
+           <color alpha="255">
+            <red>255</red>
+            <green>0</green>
+            <blue>0</blue>
+           </color>
+          </brush>
+         </colorrole>
+        </inactive>
+        <disabled>
+         <colorrole role="Base">
+          <brush brushstyle="SolidPattern">
+           <color alpha="255">
+            <red>255</red>
+            <green>255</green>
+            <blue>255</blue>
+           </color>
+          </brush>
+         </colorrole>
+        </disabled>
+       </palette>
+      </property>
+      <layout class="QVBoxLayout" name="verticalLayout">
+       <item>
+        <widget class="QLabel" name="_about_text">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt;This software is ©2010 Jochen Becher.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:18pt;&quot;&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt;Movies, Theaters, Schedules and GPS Locations use &lt;/span&gt;&lt;a href=&quot;http://www.google.com&quot;&gt;&lt;span style=&quot; font-size:18pt; font-weight:600; text-decoration: underline; color:#2eacff;&quot;&gt;Google&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt; services.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:18pt;&quot;&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:14pt;&quot;&gt;This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+         <property name="textFormat">
+          <enum>Qt::RichText</enum>
+         </property>
+         <property name="scaledContents">
+          <bool>true</bool>
+         </property>
+         <property name="alignment">
+          <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+         <property name="openExternalLinks">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="QPushButton" name="_contact_button">
+     <property name="text">
+      <string>Contact</string>
+     </property>
+     <property name="autoDefault">
+      <bool>false</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="1">
+    <widget class="QPushButton" name="_done_button">
+     <property name="text">
+      <string>Done</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/ui/abstractmainwindow.cpp b/src/ui/abstractmainwindow.cpp
new file mode 100644 (file)
index 0000000..83af9ac
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "abstractmainwindow.h"
+
+#include <QContextMenuEvent>
+
+AbstractMainWindow::AbstractMainWindow(QWidget *parent)
+    : QMainWindow(parent)
+{
+}
+
+void AbstractMainWindow::SetBusy(bool busy)
+{
+#ifdef Q_WS_MAEMO_5
+    setAttribute(Qt::WA_Maemo5ShowProgressIndicator, busy);
+#else
+    if (busy) {
+        setCursor(QCursor(Qt::WaitCursor));
+    } else {
+        setCursor(QCursor());
+    }
+#endif
+}
diff --git a/src/ui/abstractmainwindow.h b/src/ui/abstractmainwindow.h
new file mode 100644 (file)
index 0000000..2a70c68
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef ABSTRACTMAINWINDOW_H
+#define ABSTRACTMAINWINDOW_H
+
+#include <QMainWindow>
+#include <QPoint>
+
+class AbstractMainWindow : public QMainWindow
+{
+    Q_OBJECT
+public:
+    explicit AbstractMainWindow(QWidget *parent = 0);
+
+public:
+    Q_SLOT void SetBusy(bool busy);
+
+};
+
+#endif // ABSTRACTMAINWINDOW_H
diff --git a/src/ui/backgroundlabel.cpp b/src/ui/backgroundlabel.cpp
new file mode 100644 (file)
index 0000000..b9c622b
--- /dev/null
@@ -0,0 +1,86 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "backgroundlabel.h"
+
+#include <QPainter>
+#include <QFont>
+
+static const int MINIMUM_FONT_SIZE = 40;
+
+BackgroundLabel::BackgroundLabel(QWidget *parent)
+    : QWidget(parent),
+    _cached_label_font_size(0),
+    _cached_label_alignment(Qt::AlignHCenter | Qt::AlignTop)
+{
+}
+
+void BackgroundLabel::SetLabelText(const QString &label_text)
+{
+    _label_text = label_text;
+    _cached_label_font_size = 0;
+    update();
+}
+
+void BackgroundLabel::paintEvent(QPaintEvent *event)
+{
+    Q_UNUSED(event);
+
+    QPainter painter(this);
+
+    QFont label_font = font();
+    label_font.setWeight(QFont::Black);
+
+    painter.translate(rect().width(), 0);
+    painter.rotate(90);
+
+    QRect widget_rect = painter.worldTransform().inverted().mapRect(rect());
+    if (_cached_label_font_size <= 0 || widget_rect != _cached_widget_rect) {
+        _cached_widget_rect = widget_rect;
+        _cached_label_rect = widget_rect;
+        _cached_label_rect.setTop(_cached_label_rect.top() + 20);
+        _cached_label_alignment = Qt::AlignHCenter | Qt::AlignTop;
+        int font_size = 80;
+
+        for (;;) {
+            label_font.setPixelSize(font_size);
+            painter.setFont(label_font);
+            QRect label_rect = painter.boundingRect(_cached_label_rect, _cached_label_alignment, _label_text);
+            if (label_rect.x() < _cached_widget_rect.x()
+                || label_rect.y() < _cached_widget_rect.y()
+                || label_rect.width() > _cached_widget_rect.width()
+                || label_rect.height() > _cached_widget_rect.height()) {
+                font_size = font_size * 0.9;
+                if (font_size < MINIMUM_FONT_SIZE) {
+                    font_size = MINIMUM_FONT_SIZE;
+                    _cached_label_alignment = Qt::AlignLeft | Qt::AlignTop;
+                    break;
+                }
+            } else {
+                break;
+            }
+        }
+        _cached_label_font_size = font_size;
+    } else {
+        label_font.setPixelSize(_cached_label_font_size);
+        painter.setFont(label_font);
+    }
+    QColor text_color = palette().color(QPalette::WindowText);
+    text_color.setAlpha(32);
+    painter.setPen(text_color);
+    painter.drawText(_cached_label_rect, _cached_label_alignment, _label_text);
+}
diff --git a/src/ui/backgroundlabel.h b/src/ui/backgroundlabel.h
new file mode 100644 (file)
index 0000000..1eb2123
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef BACKGROUNDLABEL_H
+#define BACKGROUNDLABEL_H
+
+#include <QWidget>
+
+class BackgroundLabel : public QWidget
+{
+    Q_OBJECT
+public:
+    BackgroundLabel(QWidget *parent);
+
+public slots:
+    void SetLabelText(const QString &label_text);
+
+protected:
+    void paintEvent(QPaintEvent *event);
+
+private:
+    QString _label_text;
+    QRect _cached_widget_rect;
+    QRect _cached_label_rect;
+    int _cached_label_font_size;
+    Qt::Alignment _cached_label_alignment;
+};
+
+#endif // BACKGROUNDLABEL_H
diff --git a/src/ui/cinemapainter.cpp b/src/ui/cinemapainter.cpp
new file mode 100644 (file)
index 0000000..0740a68
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "cinemapainter.h"
+
+#include "data/cinema.h"
+#include "ui/styleutils.h"
+
+#include <QPainter>
+#include <QStyleOptionViewItem>
+
+CinemaPainter::CinemaPainter()
+{
+}
+
+void CinemaPainter::Paint(QPainter *painter, const QStyleOptionViewItem &option, const Cinema *cinema) const
+{
+    painter->setFont(option.font);
+    painter->setPen(StyleUtils::INSTANCE()->GetColor(option.palette, StyleUtils::DefaultTextColor));
+    painter->drawText(0, painter->fontMetrics().ascent(), cinema->GetName());
+    int y = painter->fontMetrics().height() + 2;
+    QRect bounding_rect;
+    painter->setPen(StyleUtils::INSTANCE()->GetColor(option.palette, StyleUtils::SecondaryTextColor));
+    bool drawn = false;
+    if (!cinema->GetAddress().isEmpty()) {
+        QFont font2(option.font);
+        font2.setPointSizeF(font2.pointSizeF() * 0.7);
+        painter->setFont(font2);
+        painter->drawText(0, y, 1000, painter->fontMetrics().height(),
+                          0, cinema->GetAddress(), &bounding_rect);
+        drawn = true;
+    }
+    if (!cinema->GetTelephone().isEmpty()) {
+        painter->drawText(bounding_rect.right(), y, 1000, painter->fontMetrics().height(),
+                          0, QString((drawn ? ", %1" : "%1")).arg(cinema->GetTelephone()), &bounding_rect);
+    }
+}
+
+QSize CinemaPainter::GetSizeHint(const QStyleOptionViewItem &option) const
+{
+    return QSize(0, option.fontMetrics.height() + 2 + option.fontMetrics.height() * 0.7 + 4);
+}
diff --git a/src/ui/cinemapainter.h b/src/ui/cinemapainter.h
new file mode 100644 (file)
index 0000000..359efa3
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef CINEMAPAINTER_H
+#define CINEMAPAINTER_H
+
+#include <QSize>
+
+class QPainter;
+class QStyleOptionViewItem;
+class Cinema;
+
+class CinemaPainter
+{
+public:
+    CinemaPainter();
+
+    void Paint(QPainter *painter, const QStyleOptionViewItem &option, const Cinema *cinema) const;
+
+    QSize GetSizeHint(const QStyleOptionViewItem &option) const;
+
+};
+
+#endif // CINEMAPAINTER_H
diff --git a/src/ui/contextdialog.cpp b/src/ui/contextdialog.cpp
new file mode 100644 (file)
index 0000000..6122238
--- /dev/null
@@ -0,0 +1,138 @@
+// Copyright 2010 Jochen Becher
+//
+// This file is part of MovieSchedule.
+//
+// MovieSchedule is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// MovieSchedule 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 MovieSchedule.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "contextdialog.h"
+#include "ui_contextdialog.h"
+
+#include "data/cinemaschedule.h"
+#include "data/scheduleentrykey.h"
+#include "data/cinema.h"
+#include "data/movie.h"
+#include "utils/assertedlocker.h"
+
+#include <QLayoutItem>
+
+ContextDialog::ContextDialog(CinemaSchedule *cinema_schedule, QWidget *parent) :
+        QDialog(parent),
+        ui(new Ui::ContextDialog),
+        _cinema_schedule(cinema_schedule),
+        _next_row(0),
+        _next_column(0)
+{
+    ui->setupUi(this);
+    removeAllWidgets();
+    connect(ui->add_to_calendar, SIGNAL(clicked()), this, SLOT(AddToCalendar()));
+    connect(ui->call_theater_by_phone, SIGNAL(clicked()), this, SLOT(CallTheaterByPhone()));
+    connect(ui-&