diff options
62 files changed, 5939 insertions, 5 deletions
@@ -1,2 +1,10 @@ -*.pro.user* -Makefile* +*Makefile +*.pro.user +*.moc +moc_* +ui_* +.build +*.app +.DS_STORE +*.so* +*.o diff --git a/LICENSE.GPLv3 b/LICENSE.GPLv3 new file mode 100644 index 0000000..3281f07 --- /dev/null +++ b/LICENSE.GPLv3 @@ -0,0 +1,684 @@ + GNU GENERAL PUBLIC LICENSE + + Qt IVI is Copyright (C) 2015 Pelagicore AG + Contact: http://www.pelagicore.com/ + + You may use, distribute and copy Qt IVI under the terms of the + GNU General Public License version 3, which is displayed below. + +------------------------------------------------------------------------- + + 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/examples/examples.pro b/examples/examples.pro index f871e51..ee83e25 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -1,4 +1,5 @@ TEMPLATE = subdirs +SUBDIRS = vehiclefunctions qtHaveModule(geniviextras) { SUBDIRS += geniviextras } diff --git a/examples/vehiclefunctions/climate_qml/climate_qml.pro b/examples/vehiclefunctions/climate_qml/climate_qml.pro new file mode 100644 index 0000000..370208f --- /dev/null +++ b/examples/vehiclefunctions/climate_qml/climate_qml.pro @@ -0,0 +1,10 @@ +TEMPLATE = app + +QT += qml quick widgets + +SOURCES += main.cpp + +RESOURCES += qml.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = diff --git a/examples/vehiclefunctions/climate_qml/main.cpp b/examples/vehiclefunctions/climate_qml/main.cpp new file mode 100644 index 0000000..09419aa --- /dev/null +++ b/examples/vehiclefunctions/climate_qml/main.cpp @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QApplication> +#include <QQmlApplicationEngine> + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + return app.exec(); +} diff --git a/examples/vehiclefunctions/climate_qml/main.qml b/examples/vehiclefunctions/climate_qml/main.qml new file mode 100644 index 0000000..07556ca --- /dev/null +++ b/examples/vehiclefunctions/climate_qml/main.qml @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.4 +import QtQuick.Controls 1.3 +import QtQuick.Window 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Dialogs 1.2 + +import QtIVICore 1.0 +import QtIVIVehicleFunctions 1.0 + +ApplicationWindow { + title: "Climate Control" + width: 384 + height: 324 + visible: true + + + ColumnLayout { + anchors.fill: parent + anchors.margins: 10 + + GroupBox { + title: "Air Flow Direction" + + ColumnLayout { + anchors.fill: parent + ExclusiveGroup { id: group } + RadioButton { + text: "Floor Panel" + exclusiveGroup: group + checked: climateControl.airflowDirection === ClimateControl.FloorPanel + onClicked: { + if (checked) + climateControl.airflowDirection = ClimateControl.FloorPanel + } + } + + RadioButton { + text: "Floor Duct" + exclusiveGroup: group + checked: climateControl.airflowDirection === ClimateControl.FloorDuct + onClicked: { + if (checked) + climateControl.airflowDirection = ClimateControl.FloorDuct + } + } + + RadioButton { + text: "Bi Level" + exclusiveGroup: group + checked: climateControl.airflowDirection === ClimateControl.BiLevel + onClicked: { + if (checked) + climateControl.airflowDirection = ClimateControl.BiLevel + } + } + + RadioButton { + text: "Defrost Floor" + exclusiveGroup: group + checked: climateControl.airflowDirection === ClimateControl.DefrostFloor + onClicked: { + if (checked) + climateControl.airflowDirection = ClimateControl.DefrostFloor + } + } + } + } + + CheckBox { + text: "Air Condition" + checked: climateControl.airConditioning + onClicked: { + climateControl.airConditioning = checked + } + } + + CheckBox { + text: "Heater" + checked: climateControl.heater + onClicked: { + climateControl.heater = checked + } + } + + CheckBox { + text: "Air Recirculation" + checked: climateControl.airRecirculation + onClicked: { + climateControl.airRecirculation = checked + } + } + + GroupBox { + title: "Front Left Zone" + + ColumnLayout { + RowLayout { + + Label { + text: "Fan Speed" + } + + SpinBox { + value: climateControl.Zones.frontLeft.fanSpeedLevel + onValueChanged: { + climateControl.Zones.frontLeft.fanSpeedLevel = value + } + } + } + + + RowLayout { + + Label { + text: "Steering Wheel Heater" + } + + SpinBox { + value: climateControl.Zones.frontLeft.steeringWheelHeater + onValueChanged: { + climateControl.Zones.frontLeft.steeringWheelHeater = value + } + } + } + } + } + } + + ClimateControl { + id: climateControl + autoDiscovery: true + } + + MessageDialog { + id: messageDialog + title: "Auto Discovery Failed !" + text: "No Climate Backend available" + icon: StandardIcon.Critical + } + + Component.onCompleted: { + if (!climateControl.isValid) + messageDialog.open() + } +} diff --git a/examples/vehiclefunctions/climate_qml/qml.qrc b/examples/vehiclefunctions/climate_qml/qml.qrc new file mode 100644 index 0000000..5f6483a --- /dev/null +++ b/examples/vehiclefunctions/climate_qml/qml.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>main.qml</file> + </qresource> +</RCC> diff --git a/examples/vehiclefunctions/climate_widget/climate_widget.pro b/examples/vehiclefunctions/climate_widget/climate_widget.pro new file mode 100644 index 0000000..2e5e746 --- /dev/null +++ b/examples/vehiclefunctions/climate_widget/climate_widget.pro @@ -0,0 +1,14 @@ +QT += core gui ivicore ivivehiclefunctions + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = climate_widget +TEMPLATE = app + + +SOURCES += main.cpp\ + mainwindow.cpp + +HEADERS += mainwindow.h + +FORMS += mainwindow.ui diff --git a/examples/vehiclefunctions/climate_widget/main.cpp b/examples/vehiclefunctions/climate_widget/main.cpp new file mode 100644 index 0000000..bec5ca5 --- /dev/null +++ b/examples/vehiclefunctions/climate_widget/main.cpp @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/examples/vehiclefunctions/climate_widget/mainwindow.cpp b/examples/vehiclefunctions/climate_widget/mainwindow.cpp new file mode 100644 index 0000000..40d0e44 --- /dev/null +++ b/examples/vehiclefunctions/climate_widget/mainwindow.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include <QMessageBox> +#include <QSpinBox> +#include <QButtonGroup> + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow), + m_radioButtonGroup(new QButtonGroup(this)), + m_climateControl(0) +{ + ui->setupUi(this); + + m_radioButtonGroup->addButton(ui->rb_BiLevel); + m_radioButtonGroup->addButton(ui->rb_DefrostFloor); + m_radioButtonGroup->addButton(ui->rb_FloorDuct); + m_radioButtonGroup->addButton(ui->rb_FloorPanel); + + m_climateControl = new QtIVIClimateControl(this); + m_climateControl->startAutoDiscovery(); + + if (!m_climateControl->isValid()) + QMessageBox::critical(this, "Auto Discovery Failed !", "No Climate Backend available"); + + setupUI(); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::setupUI() +{ + //Air Flow Direction + setupFlowDirectionRadioButtons(m_climateControl->airflowDirection()); + connect(m_radioButtonGroup, static_cast<void (QButtonGroup::*)(QAbstractButton *, bool)>(&QButtonGroup::buttonToggled), this, &MainWindow::onFlowDirectionButtonToggled); + connect(m_climateControl, &QtIVIClimateControl::airflowDirectionChanged, this, &MainWindow::setupFlowDirectionRadioButtons); + + //Air Condition + ui->cb_airCondition->setChecked(m_climateControl->isAirConditioningEnabled()); + connect(m_climateControl, &QtIVIClimateControl::airConditioningEnabledChanged, ui->cb_airCondition, &QCheckBox::setChecked); + connect(ui->cb_airCondition, &QCheckBox::clicked, m_climateControl, &QtIVIClimateControl::setAirConditioningEnabled); + + //Air Recirculation + ui->cb_airRecirculation->setChecked(m_climateControl->isAirRecirculationEnabled()); + connect(m_climateControl, &QtIVIClimateControl::airRecirculationEnabledChanged, ui->cb_airRecirculation, &QCheckBox::setChecked); + connect(ui->cb_airRecirculation, &QCheckBox::clicked, m_climateControl, &QtIVIClimateControl::setAirRecirculationEnabled); + + //Heater + ui->cb_heater->setChecked(m_climateControl->isHeaterEnabled()); + connect(m_climateControl, &QtIVIClimateControl::heaterEnabledChanged, ui->cb_heater, &QCheckBox::setChecked); + connect(ui->cb_heater, &QCheckBox::clicked, m_climateControl, &QtIVIClimateControl::setHeaterEnabled); +} + +void MainWindow::setupFlowDirectionRadioButtons(QtIVIClimateControl::AirflowDirection direction) +{ + QAbstractButton* button = ui->rb_BiLevel; + + if (direction == QtIVIClimateControl::BiLevel) + button = ui->rb_BiLevel; + else if (direction == QtIVIClimateControl::DefrostFloor) + button = ui->rb_DefrostFloor; + else if (direction == QtIVIClimateControl::FloorDuct) + button = ui->rb_FloorDuct; + else if (direction == QtIVIClimateControl::FloorPanel) + button = ui->rb_FloorPanel; + + button->setChecked(true); +} + +void MainWindow::onFlowDirectionButtonToggled(QAbstractButton *button, bool checked) +{ + if (!checked) + return; + + QtIVIClimateControl::AirflowDirection direction = QtIVIClimateControl::BiLevel; + + if (button == ui->rb_BiLevel) + direction = QtIVIClimateControl::BiLevel; + else if (button == ui->rb_DefrostFloor) + direction = QtIVIClimateControl::DefrostFloor; + else if (button == ui->rb_FloorDuct) + direction = QtIVIClimateControl::FloorDuct; + else if (button == ui->rb_FloorPanel) + direction = QtIVIClimateControl::FloorPanel; + + m_climateControl->setAirflowDirection(direction); +} diff --git a/examples/vehiclefunctions/climate_widget/mainwindow.h b/examples/vehiclefunctions/climate_widget/mainwindow.h new file mode 100644 index 0000000..77be8b5 --- /dev/null +++ b/examples/vehiclefunctions/climate_widget/mainwindow.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> +#include <QtIVIVehicleFunctions/QtIVIClimateControl> + +namespace Ui { +class MainWindow; +} + +class QButtonGroup; +class QAbstractButton; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + + void setupUI(); + +private slots: + void setupFlowDirectionRadioButtons(QtIVIClimateControl::AirflowDirection direction); + void onFlowDirectionButtonToggled(QAbstractButton * button, bool checked); + +private: + + Ui::MainWindow *ui; + QButtonGroup *m_radioButtonGroup; + QtIVIClimateControl* m_climateControl; +}; + +#endif // MAINWINDOW_H diff --git a/examples/vehiclefunctions/climate_widget/mainwindow.ui b/examples/vehiclefunctions/climate_widget/mainwindow.ui new file mode 100644 index 0000000..88e7331 --- /dev/null +++ b/examples/vehiclefunctions/climate_widget/mainwindow.ui @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>384</width> + <height>236</height> + </rect> + </property> + <property name="windowTitle"> + <string>Climate Control</string> + </property> + <widget class="QWidget" name="centralWidget"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QGroupBox" name="airFlowDirection"> + <property name="title"> + <string>Air Flow Direction</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QRadioButton" name="rb_FloorPanel"> + <property name="text"> + <string>Floor Panel</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="rb_FloorDuct"> + <property name="text"> + <string>Floor Duct</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="rb_BiLevel"> + <property name="text"> + <string>Bi &Level</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="rb_DefrostFloor"> + <property name="text"> + <string>Defrost Floor</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cb_airCondition"> + <property name="text"> + <string>Air Condition</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cb_heater"> + <property name="text"> + <string>Heater</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cb_airRecirculation"> + <property name="text"> + <string>Air Recirculation</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources/> + <connections/> +</ui> diff --git a/examples/vehiclefunctions/vehiclefunctions.pro b/examples/vehiclefunctions/vehiclefunctions.pro new file mode 100644 index 0000000..461c914 --- /dev/null +++ b/examples/vehiclefunctions/vehiclefunctions.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + climate_widget \ + climate_qml diff --git a/qtivi.pro b/qtivi.pro new file mode 100644 index 0000000..fbf1f45 --- /dev/null +++ b/qtivi.pro @@ -0,0 +1,17 @@ +enable-examples { + QTIVI_BUILD_PARTS = $$QT_BUILD_PARTS + QTIVI_BUILD_PARTS *= examples +} + +enable-tests { + QTIVI_BUILD_PARTS = $$QT_BUILD_PARTS + QTIVI_BUILD_PARTS *= tests +} + +QML_IMPORT_PATH = $$shadowed($$PWD)/qml + +lessThan(QT_MAJOR_VERSION, 5): error("QtIVI only supports Qt 5.") +load(configure) +load(qt_parts) + +OTHER_FILES += sync.profile diff --git a/src/imports/core/core.pro b/src/imports/core/core.pro new file mode 100644 index 0000000..7081aa6 --- /dev/null +++ b/src/imports/core/core.pro @@ -0,0 +1,14 @@ +CXX_MODULE = qml +TARGET = qtivicoreplugin +TARGETPATH = QtIVICore + +SOURCES += \ + plugin.cpp + +QT += ivicore + +load(qml_plugin) + +qml_files = $$_PRO_FILE_PWD_/qmldir +OTHER_FILES += $$qml_files +QMAKE_POST_LINK += $$QMAKE_COPY $$qml_files $$DESTDIR diff --git a/src/imports/core/plugin.cpp b/src/imports/core/plugin.cpp new file mode 100644 index 0000000..543a6af --- /dev/null +++ b/src/imports/core/plugin.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtQml/qqmlextensionplugin.h> +#include <qqml.h> + +#include <QtIVICore/QtIVICore> + +QT_BEGIN_NAMESPACE + +class QtIVICorePlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") +public: + virtual void registerTypes(const char *uri) + { + Q_ASSERT(QLatin1String(uri) == QLatin1String("QtIVICore")); + Q_UNUSED(uri); + + qmlRegisterUncreatableType<QtIVIZonesAttached>(uri, 1, 0, "Zones", "Zones is only accessible as attached properties"); + qmlRegisterUncreatableType<QtIVIServiceObject>(uri, 1, 0, "QtIVIServiceObject", "QtIVIServiceObject is not accessible directly"); + } +}; + +QT_END_NAMESPACE + +#include "plugin.moc" diff --git a/src/imports/core/qmldir b/src/imports/core/qmldir new file mode 100644 index 0000000..1edec73 --- /dev/null +++ b/src/imports/core/qmldir @@ -0,0 +1,3 @@ +module QtIVICore +plugin qtivicoreplugin +classname QtIVICorePlugin diff --git a/src/imports/imports.pro b/src/imports/imports.pro new file mode 100644 index 0000000..c862df4 --- /dev/null +++ b/src/imports/imports.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +SUBDIRS = core \ + vehiclefunctions + diff --git a/src/imports/vehiclefunctions/plugin.cpp b/src/imports/vehiclefunctions/plugin.cpp new file mode 100644 index 0000000..da4b197 --- /dev/null +++ b/src/imports/vehiclefunctions/plugin.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQml/qqmlextensionplugin.h> +#include <qqml.h> + +#include <QtIVIVehicleFunctions/QtIVIClimateControl> + +QT_BEGIN_NAMESPACE + +class QtIVIVehicleFunctionsPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") +public: + virtual void registerTypes(const char *uri) + { + Q_ASSERT(QLatin1String(uri) == QLatin1String("QtIVIVehicleFunctions")); + Q_UNUSED(uri); + + qmlRegisterType<QtIVIClimateControl>(uri, 1, 0, "ClimateControl"); + qmlRegisterUncreatableType<QtIVIClimateZone>(uri, 1, 0, "ClimateZone", "ClimateZone only accessible from ClimateControl"); + } +}; + +QT_END_NAMESPACE + +#include "plugin.moc" diff --git a/src/imports/vehiclefunctions/qmldir b/src/imports/vehiclefunctions/qmldir new file mode 100644 index 0000000..2c3c28e --- /dev/null +++ b/src/imports/vehiclefunctions/qmldir @@ -0,0 +1,3 @@ +module QtIVIVehicleFunctions +plugin qtivivehiclefunctionsplugin +classname QtIVIVehicleFunctionsPlugin diff --git a/src/imports/vehiclefunctions/vehiclefunctions.pro b/src/imports/vehiclefunctions/vehiclefunctions.pro new file mode 100644 index 0000000..39722f9 --- /dev/null +++ b/src/imports/vehiclefunctions/vehiclefunctions.pro @@ -0,0 +1,14 @@ +CXX_MODULE = qml +TARGET = qtivivehiclefunctionsplugin +TARGETPATH = QtIVIVehicleFunctions + +SOURCES += \ + plugin.cpp + +QT += ivicore ivivehiclefunctions + +load(qml_plugin) + +qml_files = $$_PRO_FILE_PWD_/qmldir +OTHER_FILES += $$qml_files +QMAKE_POST_LINK += $$QMAKE_COPY $$qml_files $$DESTDIR diff --git a/src/ivicore/doc/qtivicore.qdocconf b/src/ivicore/doc/qtivicore.qdocconf new file mode 100644 index 0000000..7f6ee99 --- /dev/null +++ b/src/ivicore/doc/qtivicore.qdocconf @@ -0,0 +1,52 @@ +include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) + +project = QtIVICore +description = Qt IVI Core Reference Documentation +version = $QT_VERSION + + + +qhp.projects = QtIVICore + +qhp.QtIVICore.file = qtivicore.qhp +qhp.QtIVICore.namespace = org.qt-project.qtivicore.$QT_VERSION_TAG +qhp.QtIVICore.virtualFolder = qtivicore +qhp.QtIVICore.indexTitle = Qt IVI Core +qhp.QtIVICore.indexRoot = + +qhp.QtIVICore.filterAttributes = qtivicore $QT_VERSION qtrefdoc +qhp.QtIVICore.customFilters.Qt.name = QtIVICore $QT_VERSION +qhp.QtIVICore.customFilters.Qt.filterAttributes = qtIVICore $QT_VERSION +qhp.QtIVICore.subprojects = overviews classes qml examples +qhp.QtIVICore.subprojects.classes.title = C++ Classes +qhp.QtIVICore.subprojects.classes.indexTitle = Qt IVI Core C++ Classes +qhp.QtIVICore.subprojects.classes.selectors = class fake:headerfile +qhp.QtIVICore.subprojects.classes.sortPages = true +qhp.QtIVICore.subprojects.qml.title = QML Types +qhp.QtIVICore.subprojects.qml.indexTitle = Qt IVI Core QML Types +qhp.QtIVICore.subprojects.qml.selectors = fake:headerfile +qhp.QtIVICore.subprojects.qml.sortPages = true +qhp.QtIVICore.subprojects.overviews.title = Overviews +qhp.QtIVICore.subprojects.overviews.indexTitle = Qt IVI Core Overview +qhp.QtIVICore.subprojects.overviews.selectors = fake:page,group,module +qhp.QtIVICore.subprojects.examples.title = Qt IVI Core Examples +qhp.QtIVICore.subprojects.examples.indexTitle = Qt IVI Core Examples +qhp.QtIVICore.subprojects.examples.selectors = fake:example + +tagfile = ../../../doc/qtivicore/qtivicore.tags + +depends += qtcore qtdoc qtquick qtqml + +headerdirs += .. \ + ../../imports/core + +sourcedirs += .. \ + ../../imports/core \ + +examplesinstallpath = qtivicore + +#imagedirs += images + +navigation.landingpage = "Qt IVI Core" +navigation.cppclassespage = "Qt IVI Core C++ Classes" +navigation.qmltypespage = "Qt IVI Core QML Types" diff --git a/src/ivicore/ivicore.pro b/src/ivicore/ivicore.pro new file mode 100644 index 0000000..2b19da0 --- /dev/null +++ b/src/ivicore/ivicore.pro @@ -0,0 +1,31 @@ +TARGET = QtIVICore + +QT = core core-private qml +CONFIG += c++11 +VERSION = 1.0.0 + +QMAKE_DOCS = $$PWD/doc/qtivicore.qdocconf +OTHER_FILES += $$PWD/doc/*.qdoc + +CMAKE_MODULE_TESTS = '-' + +HEADERS += \ + qtiviservicemanager.h \ + qtiviserviceinterface.h \ + qtiviservicemanager_p.h \ + qtiviserviceobject.h \ + qtiviabstractfeature.h \ + qtiviglobal.h \ + qtiviproxyserviceobject_p.h \ + qtivizonesattached.h \ + qtiviabstractzonemodelfeature.h + +SOURCES += \ + qtiviservicemanager.cpp \ + qtiviserviceobject.cpp \ + qtiviabstractfeature.cpp \ + qtiviproxyserviceobject_p.cpp \ + qtivizonesattached.cpp \ + qtiviabstractzonemodelfeature.cpp + +load(qt_module) diff --git a/src/ivicore/qtiviabstractfeature.cpp b/src/ivicore/qtiviabstractfeature.cpp new file mode 100644 index 0000000..f351f14 --- /dev/null +++ b/src/ivicore/qtiviabstractfeature.cpp @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtiviabstractfeature.h" + +#include "qtiviserviceobject.h" +#include "qtiviservicemanager.h" + +/*! + * \class QtIVIAbstractFeature + * \inmodule QtIVICore + * \brief The QtIVIAbstractFeature is the base class for all QtIVI Featues + * + * QtIVIAbstractFeature is the base class for the front facing API towards the Developer. + * The QtIVIAbstractFeature provides you with a way to automatically connect to a Backend implementing + * your needed interface. This discovery is started by using the startAutoDiscovery() function. + * + * Once the auto discovery is done, it can be checked whether a backend has been found by using the + * isValid function. + * + * The auto discovery gives you a easy way to automatically connect to the right backend implementation. + * If you don't want to use the auto discovery, it's also possible to use QtIVIServiceManager to retrieve + * all Backends and search manually for the right one and connect it to the QtIVIAbstractFeature by calling + * setServiceObject() + * + * QtIVIAbstractFeature is a abstract base class which needs to be subclassed to create a API for your + * Feature. + * + * \chapter Subclassing + * + * When subclassing QtIVIAbstractFeature you must provide implementations of the following functions: + * \list + * \li acceptServiceObject() + * \li connectToServiceObject() + * \li disconnectFromServiceObject() + * \li clearServiceObject() + * \endlist + * + * Once a QtIVIServiceObject has be set, either by auto discovery or by manually setting it the acceptServiceObject() + * function will be called to make sure the QtIVIServiceObject provides everything which is needed by the Feature. + * + * If the interface provides signals you need to do all the connect statements in connectToServiceObject() and + * disconnect them again in disconnectFromServiceObject(). + * + * clearServiceObject() will be called once the Feature doesn't have a connection to a ServiceObject anymore and should + * reset it's state to sane defaults + */ + +/*! + * \fn bool QtIVIAbstractFeature::acceptServiceObject(QtIVIServiceObject *so) + * + * This method is expected to be implemented by any class subclassing QtIVIAbstractFeature. + * + * This method is expected to return \c true if the given service object, \a so, is accepted and + * can be used, otherwise \c false. + * + * If the object is accepted, \l connectToServiceObject is called to actually connect to the + * service object. + * + * \sa connectToServiceObject(), disconnectFromServiceObject(), clearServiceObject() + */ + +/*! + * \fn void QtIVIAbstractFeature::connectToServiceObject(QtIVIServiceObject *so) + * + * This method is expected to be implemented by any class subclassing QtIVIAbstractFeature. + * + * The implementation is expected to connect to the service object, \a so, and to set all + * properties to reflect the state of the service object. + * + * There is no previous service object connected, as this call always is preceeded by a call to + * \l disconnectFromServiceObject or \l clearServiceObject. + * + * It is safe to assume that the service object, \a so, has always been accepted through the + * \l acceptServiceObject method prior to being passed to this method. + * + * \sa acceptServiceObject(), disconnectFromServiceObject(), clearServiceObject() + */ + +/*! + * \fn void QtIVIAbstractFeature::disconnectFromServiceObject(QtIVIServiceObject *so) + * + * This method is expected to be implemented by any class subclassing QtIVIAbstractFeature. + * + * The implementation is expected to disconnect from the service object, \a so. + * + * It is not expected that the implementation goes to safe defaults. A call to this function is + * always followed by a call to \l connectToServiceObject or \l clearServiceObject. + * + * \sa acceptServiceObject(), connectToServiceObject(), clearServiceObject() + */ + +/*! + * \fn void QtIVIAbstractFeature::clearServiceObject() + * + * This method is expected to be implemented by any class subclassing QtIVIAbstractFeature. + * + * Called when no service object is available. The implementation is expected to set all + * properties to safe defaults and forget all links to the previous service object. + * + * There is no need to disconnect from the service object. If it still exists, it is guaranteed + * that \l disconnectFromServiceObject is called first. + * + * \sa acceptServiceObject(), connectToServiceObject(), disconnectFromServiceObject() + */ + +/*! + * Constructs an abstract feature. + * + * The \a parent argument is passed on to the \l QObject constructor. + * + * The \a interface argument is used to locate suitable service objects. + * + * The \a autoDiscovery argument is used to define the default \l autoDiscovery state. + */ +QtIVIAbstractFeature::QtIVIAbstractFeature(const QString &interface, bool autoDiscovery, QObject *parent) + : QObject(parent) + , m_interface(interface) + , m_serviceObject(0) + , m_autoDiscovery(autoDiscovery) +{ + //Detect whether we got created from within QML + //If not call the autoDiscovery +} + +/*! + * Destructor. + */ +QtIVIAbstractFeature::~QtIVIAbstractFeature() +{ + +} + +/*! + * \property QtIVIAbstractFeature::serviceObject + * \brief Sets the service object for the feature. + * + * As features only expose the front API facing the developer, a service object implementing the + * actual function is required. This is usually retrieved through the \l autoDiscovery mechanism. + * + * \sa autoDiscovery + */ +void QtIVIAbstractFeature::setServiceObject(QtIVIServiceObject *so) +{ + if (m_serviceObject) { + disconnectFromServiceObject(m_serviceObject); + disconnect(so, SIGNAL(destroyed()), this, SLOT(serviceObjectDestroyed())); + } + + m_serviceObject = 0; + + if (!acceptServiceObject(so)) { + clearServiceObject(); + qWarning("ServiceObject is not accepted"); + } + + m_serviceObject = so; + emit serviceObjectChanged(); + emit isValidChanged(isValid()); + connectToServiceObject(m_serviceObject); + connect(so, SIGNAL(destroyed()), this, SLOT(serviceObjectDestroyed())); +} + +/*! + * \property QtIVIAbstractFeature::autoDiscovery + * \brief \c True if service objects are located automatically. + * + * If auto discovery is enabled the feature will search for a suitable backend when either + * \l componentComplete is called from QML or \l startAutoDiscovery is called from C++. + * + * \sa startAutoDiscovery(), componentComplete + */ +void QtIVIAbstractFeature::setAutoDiscovery(bool autoDiscovery) +{ + if (m_autoDiscovery == autoDiscovery) + return; + + m_autoDiscovery = autoDiscovery; + emit autoDiscoveryChanged(autoDiscovery); +} + +/*! + * \internal + * Overloaded from \l QQmlParserStatus. + */ +void QtIVIAbstractFeature::classBegin() +{ + +} + +/*! + * Invoked automatically when used from QML. Calls \l startAutoDiscovery if \l autoDiscovery is \c true. + */ +void QtIVIAbstractFeature::componentComplete() +{ + if (m_autoDiscovery) { + startAutoDiscovery(); + } +} + +QtIVIServiceObject *QtIVIAbstractFeature::serviceObject() const +{ + return m_serviceObject; +} + +bool QtIVIAbstractFeature::autoDiscovery() const +{ + return m_autoDiscovery; +} + +/*! + * \brief Performs an auto discovery attempt. + * + * The feature will try to locate a single service object implementing the required interface. + * + * If no service object is found, the feature will stay invalid. If more than one service object + * is found, the first instance is used. + * + * This function enabled the \l autoDiscovery property. + * + * \sa autoDiscovery + */ +void QtIVIAbstractFeature::startAutoDiscovery() +{ + setAutoDiscovery(true); + + if (m_serviceObject) // No need to discover a new backend when we already have one + return; + + QtIVIServiceManager* serviceManager = QtIVIServiceManager::instance(); + QList<QtIVIServiceObject*> serviceObjects = serviceManager->findServiceByInterface(m_interface); + + if (serviceObjects.isEmpty()) { + qWarning() << "There is no backend implementing" << m_interface << "."; + return; + } + + if (serviceObjects.count() > 1) + qWarning() << "There is more than one backend implementing" << m_interface << "."; + + setServiceObject(serviceObjects.at(0)); +} + +/*! + * \property QtIVIAbstractFeature::isValid + * \brief \c True if the feature is ready to use. + * + * The valid property is \c true if the feature is ready to be used, otherwise \c false. Not being + * ready usually indicates that no suitable service object could be found or that auto discovery + * has not been triggered. + * + * \sa serviceObject, autoDiscovery + */ +bool QtIVIAbstractFeature::isValid() const +{ + return m_serviceObject != 0; +} + +void QtIVIAbstractFeature::serviceObjectDestroyed() +{ + m_serviceObject = 0; + clearServiceObject(); + emit serviceObjectChanged(); +} diff --git a/src/ivicore/qtiviabstractfeature.h b/src/ivicore/qtiviabstractfeature.h new file mode 100644 index 0000000..c04b05f --- /dev/null +++ b/src/ivicore/qtiviabstractfeature.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIVIABSTRACTFEATURE_H +#define QTIVIABSTRACTFEATURE_H + +#include <QObject> +#include <QQmlParserStatus> + +#include <QtIVICore/qtiviglobal.h> + +class QtIVIServiceObject; + +class Q_QTIVICORE_EXPORT QtIVIAbstractFeature : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + + //This makes only sense if the Object is loaded directly + //Maybe use a attached property instead ??? Feature.simulation = true; Feature.autoDiscovery = false + //Q_PROPERTY(bool simulation READ simulation WRITE setSimulation NOTIFY simulationChanged) + Q_PROPERTY(bool autoDiscovery READ autoDiscovery WRITE setAutoDiscovery NOTIFY autoDiscoveryChanged) + Q_PROPERTY(QtIVIServiceObject* serviceObject READ serviceObject WRITE setServiceObject NOTIFY serviceObjectChanged) + Q_PROPERTY(bool isValid READ isValid NOTIFY isValidChanged) + +public: + + explicit QtIVIAbstractFeature(const QString &interface, bool autoDiscovery = true, QObject *parent = 0); + virtual ~QtIVIAbstractFeature(); + + QtIVIServiceObject *serviceObject() const; + bool autoDiscovery() const; + bool isValid() const; + + void startAutoDiscovery(); + +public slots: + void setServiceObject(QtIVIServiceObject *so); + void setAutoDiscovery(bool autoDiscovery); + +signals: + void serviceObjectChanged(); + void autoDiscoveryChanged(bool autoDiscovery); + void isValidChanged(bool arg); + +protected: + + //USE acceptService instead of the interface constructor, also in the simplediscoverymodel + virtual bool acceptServiceObject(QtIVIServiceObject*) = 0; + virtual void connectToServiceObject(QtIVIServiceObject*) = 0; + virtual void disconnectFromServiceObject(QtIVIServiceObject*) = 0; + virtual void clearServiceObject() = 0; + + //TODO This doesn't work for the C++ usecases we should use the constructor there instead + // Also this means a qml dependency in the core, do we want that ? + virtual void classBegin(); + virtual void componentComplete(); + +private slots: + void serviceObjectDestroyed(); + +private: + + QString m_interface; + QtIVIServiceObject* m_serviceObject; + bool m_autoDiscovery; +}; + +#endif // QTIVIABSTRACTFEATURE_H diff --git a/src/ivicore/qtiviabstractzonemodelfeature.cpp b/src/ivicore/qtiviabstractzonemodelfeature.cpp new file mode 100644 index 0000000..751bc27 --- /dev/null +++ b/src/ivicore/qtiviabstractzonemodelfeature.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtiviabstractzonemodelfeature.h" + +#include <QAbstractItemModel> + +class QtIVIZoneModel : public QAbstractListModel +{ +public: + QtIVIZoneModel(QtIVIAbstractZoneModelFeature *parent); + + int rowCount(const QModelIndex &) const; + QVariant data(const QModelIndex &, int) const; + + QHash<int, QByteArray> roleNames() const; + + void updateModel(); + +private: + QtIVIAbstractZoneModelFeature *m_feature; +}; + +QtIVIZoneModel::QtIVIZoneModel(QtIVIAbstractZoneModelFeature *parent) + : QAbstractListModel(parent) + , m_feature(parent) +{ + connect(m_feature, SIGNAL(isValidChanged(bool)), this, SIGNAL(modelReset())); +} + +int QtIVIZoneModel::rowCount(const QModelIndex &index) const +{ + int res = 0; + + if (!index.isValid()) + res = m_feature->zones().count(); + + return res; +} + +QVariant QtIVIZoneModel::data(const QModelIndex &index, int role) const +{ + QVariant res; + + if (index.isValid() && + !index.parent().isValid() && + index.column() == 0 && + index.row() >= 0 && + index.row() < m_feature->zones().count()) { + switch(role) + { + case Qt::DisplayRole: + res = m_feature->zones().at(index.row()); + break; + case Qt::UserRole: + res = QVariant::fromValue<QObject*>(m_feature->zoneObject(m_feature->zones().at(index.row()))); + break; + } + } + + return res; +} + +QHash<int, QByteArray> QtIVIZoneModel::roleNames() const +{ + QHash<int, QByteArray> res; + + res[Qt::DisplayRole] = "zoneName"; + res[Qt::UserRole] = "zoneObject"; + + return res; +} + +void QtIVIZoneModel::updateModel() +{ + beginResetModel(); + // TODO this needs to be fixed. Right now the model is based on the contents of the backend + // and if the backend changes, we really do not know anything of the previous state, so the + // about-signal is misleading. + endResetModel(); +} + +QtIVIAbstractZoneModelFeature::QtIVIAbstractZoneModelFeature(const QString &interface, bool autoDiscovery, QObject *parent) + : QtIVIAbstractFeature(interface, autoDiscovery, parent) +{ + m_model = new QtIVIZoneModel(this); +} + +QAbstractItemModel *QtIVIAbstractZoneModelFeature::model() +{ + return m_model; +} + +void QtIVIAbstractZoneModelFeature::zonesChanged() +{ + m_model->updateModel(); +} diff --git a/src/ivicore/qtiviabstractzonemodelfeature.h b/src/ivicore/qtiviabstractzonemodelfeature.h new file mode 100644 index 0000000..4c5175e --- /dev/null +++ b/src/ivicore/qtiviabstractzonemodelfeature.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIVIABSTRACTZONEMODELFEATURE_H +#define QTIVIABSTRACTZONEMODELFEATURE_H + +#include <QtIVIAbstractFeature> + +#include <QtIVICore/qtiviglobal.h> + +class QAbstractItemModel; + +class QtIVIZoneModel; + +class Q_QTIVICORE_EXPORT QtIVIAbstractZoneModelFeature : public QtIVIAbstractFeature +{ + Q_OBJECT + + Q_PROPERTY(QAbstractItemModel* model READ model CONSTANT) + +public: + QtIVIAbstractZoneModelFeature(const QString &interface, bool autoDiscovery = true, QObject *parent = 0); + + virtual QStringList zones() const = 0; + virtual QObject *zoneObject(const QString &z) const = 0; + + QAbstractItemModel *model(); + +protected: + void zonesChanged(); + +private: + QtIVIZoneModel *m_model; +}; + +#endif // QTIVIABSTRACTZONEMODELFEATURE_H diff --git a/src/ivicore/qtiviglobal.h b/src/ivicore/qtiviglobal.h new file mode 100644 index 0000000..e83451f --- /dev/null +++ b/src/ivicore/qtiviglobal.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIVIGLOBAL_H +#define QTIVIGLOBAL_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_STATIC +# if defined(QT_BUILD_QTIVICORE_LIB) +# define Q_QTIVICORE_EXPORT Q_DECL_EXPORT +# else +# define Q_QTIVICORE_EXPORT Q_DECL_IMPORT +# endif +#else +# define Q_QTIVICORE_EXPORT +#endif + +QT_END_NAMESPACE + +#endif // QTIVIGLOBAL_H + diff --git a/src/ivicore/qtiviproxyserviceobject_p.cpp b/src/ivicore/qtiviproxyserviceobject_p.cpp new file mode 100644 index 0000000..aa6b475 --- /dev/null +++ b/src/ivicore/qtiviproxyserviceobject_p.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtiviproxyserviceobject_p.h" + +QtIVIProxyServiceObject::QtIVIProxyServiceObject(QtIVIServiceInterface *interface) + : QtIVIServiceObject() + , m_interface(interface) +{ + +} + +QtIVIProxyServiceObject::~QtIVIProxyServiceObject() +{ + +} + +QStringList QtIVIProxyServiceObject::interfaces() const +{ + return m_interface->interfaces(); +} + +QObject *QtIVIProxyServiceObject::interfaceInstance(const QString &interface) const +{ + return m_interface->interfaceInstance(interface); +} + diff --git a/src/ivicore/qtiviproxyserviceobject_p.h b/src/ivicore/qtiviproxyserviceobject_p.h new file mode 100644 index 0000000..6a19d87 --- /dev/null +++ b/src/ivicore/qtiviproxyserviceobject_p.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIVIPROXYSERVICEOBJECT_H +#define QTIVIPROXYSERVICEOBJECT_H + +#include "qtiviserviceobject.h" + +class QtIVIProxyServiceObject : public QtIVIServiceObject +{ +public: + QtIVIProxyServiceObject(QtIVIServiceInterface* interface); + virtual ~QtIVIProxyServiceObject(); + + virtual QStringList interfaces() const; + virtual QObject* interfaceInstance(const QString& interface) const; + +private: + + QtIVIServiceInterface* m_interface; +}; + +#endif // QTIVIPROXYSERVICEOBJECT_H diff --git a/src/ivicore/qtiviserviceinterface.h b/src/ivicore/qtiviserviceinterface.h new file mode 100644 index 0000000..7d4268c --- /dev/null +++ b/src/ivicore/qtiviserviceinterface.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIVISERVICEINTERFACE_H +#define QTIVISERVICEINTERFACE_H + +#include <QtPlugin> + +class QtIVIServiceInterface { + +public: + + virtual QStringList interfaces() const = 0; + virtual QObject* interfaceInstance(const QString& interface) const = 0; +}; + +Q_DECLARE_INTERFACE(QtIVIServiceInterface, "com.pelagicore.QtIVIServiceInterface") +Q_DECLARE_METATYPE(QtIVIServiceInterface*) + +#endif // QTIVISERVICEINTERFACE_H + diff --git a/src/ivicore/qtiviservicemanager.cpp b/src/ivicore/qtiviservicemanager.cpp new file mode 100644 index 0000000..8816e59 --- /dev/null +++ b/src/ivicore/qtiviservicemanager.cpp @@ -0,0 +1,602 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtiviservicemanager.h" + +#include "qtiviproxyserviceobject_p.h" +#include "qtiviservicemanager_p.h" + +#include <QStringList> +#include <QPluginLoader> +#include <QJsonObject> +#include <QCoreApplication> +#include <QDir> +#include <QModelIndex> +#include <QDebug> + +/*! + * \module QtIVICore + * + * \title Qt IVI Core Module + * + * \brief Classes for Qt IVI Extension modules. + * + * Qt IVI provides a pattern for extending Qt with extendable APIs. It also comes with a set of + * demonstrator APIs that can be used as a starting point or off-the-shelf in your projects. + * + * The pattern is based around separation of the API facing the application developer, the so + * called \e {Feature}, and the code implementing the said API, the \e {Backend}. There can be + * multiple backends per feature and the Core module provides support for finding the corresponding + * backend in an easy to use way. + * + * Common use cases driving this separation are: + * + * \list + * \li \e {Early development}, where the UI can rely on a feature with a very basic backend + * implementation. + * \li \e {Testing / Simulation}, where the backends can be tested separately from the app and the + * app can be tested using a specialized testing backend. + * \li \e {Targets with different hardware configurations}, where parts of the system is + * represented by simulated backends while others use a real hardware integration. + * \li \e {Dynamically appearing services}, when services are available sometimes, but not always, + * meaning that backends come and go over time. + * \endlist + * + * \chapter Building Blocks + * + * Qt IVI consists of a number of building blocks. Understanding the roles of these is key to using + * Qt IVI. + * + * \section1 Core + * + * The core module provides base classes for writing features and backends as well as the + * mechanisms for finding the correct backend for each feature. + * + * The core also contains common classes and base classes for various models and shared types. + * + * \section1 Feature + * + * The feature is what an application developer uses. The feature contains the API facing the + * applications, but also the backend interface, i.e. the interface that the corresponding backend + * needs to implement. The object implementing the backend interface is called as service object. + * + * The backend interface defines an interface name. This is a unique string identifying the + * interface between the feature and the backend. It is commonly written using reverse domain name + * notation, e.g. com.example.FeatureName. This is what is used by Core to find service objects + * for a feature. + * + * The feature is derived from the QtIVIAbstractFeature class. The backend interface is commonly + * based on QObject. + * + * To make the API useable from QML, the feature needs to include a QML plugin registering types + * and classes. The QML plugin is derived from the QQmlExtensionPlugin class. + * + * It is common to include a simple stubbed backend and a testing backend with each feature. + * + * \section1 Backend + * + * A backend implements the backend interface specified by the feature. The backend is derived from + * the backend interface class defined by the feature, which is a QObject derived class. + * + * The object implementing the backend is called as service object. + * + * The backends are loaded by Core when the features request them. Each backend has to provide a Qt + * IVI plugin that exposes a factory to the Core. This is what is used to load and create backends. + * The plugin interface is called QtIVIServiceInterface. + * + * \section1 Simple vs Dynamic Features + * + * Most features are simple. This means that each feature element needs a single service object. By + * setting the autoDiscover property of QtIVIAbstractFeature to true, the Core module provides the + * first compatible service object to the feature and issues a warning if none or more than one + * compatible service object is found. + * + * When auto discovery is used, Core looks for the backend once during the creation of the feature + * instance. When used from QML, this takes place when the feature element is completely + * initalized. From C++, it is made when a call to the startAutoDiscovery method is called. + * + * For dynamic features, there can be multiple service objects for each feature. This means that + * the auto discovery mechanism does not work. Instead the application must take responsibility for + * finding the right service object for each feature instance. + * + * QtIVIServiceManager can be used in this case to manually search for plugins with a specific + * BackendInterface. All the discovery and loading of the backends takes place in this class. + * + * The QtIVIServiceManager class can also be used to register backends which are part of the same + * application and shouldn’t go into a plugin. This is especially useful for autotest as you need + * to control the backend and the feature at the same time. + * + * \part Using Qt Qt IVI + * + * Qt IVI can be used using both C++ and QML. This section describes how to work with the Qt IVI + * modules from a general perspective. The actual API details for each feature is described in the + * feature documentation. + * + * \chapter From QML + * + * The QML application relies on the QML plugin loading capabilities of the Qt QML runtime. This + * means that an installed Qt IVI module is found automatically. + * + * \note For details on how to work with uninstalled modules, please refer to the \l {Extending Qt IVI} section. + * + * In the QML code, import the relevant feature modules, e.g: + * + * \code + * import QtIVIVehicleFunctions 1.0 + * \endcode + * + * Then instantiate the feature element. For most elements, autoDiscovery is set to true when + * applicable, but in this example we set it explicitly. + * + * \code + * ClimateControl { + * id: climateControl + * autoDiscovery: true + * } + * \endcode + * + * When the top-level component has been completed, the isValid property of the feature elements + * can be used to determine if any backend is missing. In some situations this is expected + * behaviour, then the isValid property can be used to enable or disable parts of the user + * interface. + * + * \code + * Component.onCompleted: { + * if (!climateControl.isValid) + * ; // Take action here + * } + * \endcode + * + * Interactions with the feature element is described in the feature documentation. It is possible + * to bind properties, call methods and listen to signals. + * + * For a complete example please have a look at the climate_qml example in the vehiclefunctions + * module. + * + * \chapter From C++ + * + * When creating a C++ application using Qt IVI, you will have to link to the relevant modules. + * This is controlled in the pro-file of your application, e.g: + * + * \code + * QT += ivivehiclefunctions + * \endcode + * + * To use feature elements, simply include the header file and instantiate the element. + * + * \code + * #include <QtIVIVehicleFunctions/QtIVIClimateControl> + * … + * QtIVIClimateControl* m_climateControl; + * m_climateControl = new QtIVIClimateControl(this); + * \endcode + * + * In order to trigger the auto discovery mechanism, call the startAutoDiscovery method. This will + * load the appropriate backend and set a service object for the feature element. Please notice + * that calling this method sets the autoDiscovery property to true. To use dynamic services, + * simply do not call this method. + * + * \code + * m_climateControl->startAutoDiscovery(); + * \endcode + * + * After the startAutoDiscovery method has been called, the isValid property can be used to + * determine if a backend was found or not. + * + * \code + * if (!m_climateControl->isValid()) + * QMessageBox::critical( … ); // Take action here + * \endcode + * + * For a complete example please have a look at the climate_widgetl example in the vehiclefunctions + * module. + * + * \part Extending Qt IVI + * + * For easy deployment, Qt IVI extensions should be built as Qt modules. This makes it easy to + * install and find headers, shared libraries as well as plugin modules from app projects. + * + * By using the module system the developer benefits from easily enable the inclusion of your + * module by using + * + * \code + * QT += <module> + * \endcode + * + * In addition your module is properly setup to also work with cmake and the qdoc environment is + * already setup, not to speak about the automatic test execution when using + * + * \code + * make tests + * \endcode + * + * When creating a new Qt IVI module, it is recommended that you pick a name such as + * \e {OemFeatureName}, where \e {Oem} is the name of the car-maker or platform owner, and + * \e {FeatureName} is the name of the feature(s) of the module. In addition to the name, a reverse + * domain name prefix is needed for prefixing backend interface names, e.g. \e {com.example}. + * + * Notice that it is possible to have multiple feature element classes in a single module. For + * instance, the media module of Qt IVI contains both source discovery, media search and media + * browse APIs. + * + * Having decided on a name and a backend interface name prefix, the template module can be checked + * out from git. Then the renamer script is used to create the module, e.g: + * + * \code + * ./renamer.sh Oem MyFeature com.pelagicore + * \endcode + * + * This will result in the \e {OemMyFeature} module to be created and the backend interfaces + * prefixed with \e {com.pelagicore}, e.g. \e {com.pelagicore.MyFeature}. + * + * The resulting directory structure is described in the table below. + * + * \table + * \header + * \li Path + * \li Description + * \row + * \li \c {examples} + * \li Examples top-level directory + * \row + * \li \c {examples/feature} + * \li Feature specific example directory + * \row + * \li \c {example/feature/feature_qml} + * \li Template QML-based feature example + * \row + * \li \c {example/feature/feature_widgets} + * \li Template widgets-based feature example + * \row + * \li \c {src} + * \li Source code top-level directory + * \row + * \li \c {src/feature} + * \li Feature source code. Includes feature APIs as well as backend interfaces + * \row + * \li \c {src/feature/doc} + * \li Feature documentation configuration + * \row + * \li \c {src/imports} + * \li QML import modules top-level directory + * \row + * \li \c {src/imports/feature} + * \li Template feature QML import module + * \row + * \li \c {src/plugins} + * \li Qt IVI backend plugins directory + * \row + * \li \c {src/plugins/feature} + * \li Feature Qt IVI backends directory + * \row + * \li \c {src/plugin/feature/feature_stub} + * \li Stubbed template feature Qt IVI backend + * \row + * \li \c {tests} + * \li Unit tests top-level directory + * \row + * \li \c {tests/auto} + * \li Automatic tests directory + * \row + * \li \c {tests/auto/feature} + * \li Template feature unit test + * \row + * \li \c {sync.profile} + * \li Qt module control script + * \endtable + * + * To add more feature APIs, simply add them into \c {src/feature} and + * \c {src/imports/feature}. To add more backends, add them to \c {src/plugins/feature}. + * + * If another OEM specific feature is needed there is no need to create the whole folder structure + * again. Simply add your feature’s code into the example \c {src} and \c {tests} folders and add + * it to the \c {sync.profile} file. + * + * To create a backend for an existing feature, simply create a new Qt project based on the feature + * module in question and build a Qt IVI backend plugin. + * + * \chapter Creating a Qt Module + * \chapter Creating a Feature + * \chapter Creating a Backend + * + */ + + +#define QTIVI_PLUGIN_DIRECTORY "qtivi" + +QtIVIServiceManagerPrivate::QtIVIServiceManagerPrivate(QtIVIServiceManager *parent) : QObject(parent), q_ptr(parent) +{ +} + +QList<QtIVIServiceObject *> QtIVIServiceManagerPrivate::findServiceByInterface(const QString &interface) +{ + QList<QtIVIServiceObject*> list; + + foreach (Backend *backend, m_backends) { + + if (backend->metaData[QLatin1String("interfaces")].toStringList().contains(interface)) { + QtIVIServiceInterface *backendInterface = loadServiceBackendInterface(backend); + list.append(new QtIVIProxyServiceObject(backendInterface)); + } + } + + return list; +} + +void QtIVIServiceManagerPrivate::searchPlugins() +{ + bool found = false; + foreach (const QString &pluginDir, QCoreApplication::libraryPaths()) { + + QDir dir(pluginDir); + QString path = pluginDir + QDir::separator() + QLatin1Literal(QTIVI_PLUGIN_DIRECTORY); + //Check whether the directory exists + if (!QDir(path).exists(QStringLiteral("."))) + continue; + + QStringList plugins = QDir(path).entryList(QDir::Files); + foreach (const QString &pluginPath, plugins) { + QString fileName = QDir::cleanPath(path + QLatin1Char('/') + pluginPath); + QPluginLoader loader(dir.absoluteFilePath(fileName)); + registerBackend(loader.fileName(), loader.metaData()); + found = true; + } + } + if (!found) + { + qWarning() << "No plugins found in search path: " << QCoreApplication::libraryPaths().join(QLatin1String(":")); + } +} + +void QtIVIServiceManagerPrivate::registerBackend(const QString fileName, const QJsonObject metaData) +{ + QVariantMap backendMetaData = metaData.value(QLatin1String("MetaData")).toVariant().toMap(); + + if (backendMetaData[QLatin1String("interfaces")].isNull() || backendMetaData[QLatin1String("interfaces")].toList().isEmpty()) { + qDebug("PluginManager - Malformed metaData in '%s'. MetaData must contain a list of interfaces", qPrintable(fileName)); + return; + } + + //TODO check for other metaData like name etc. + + backendMetaData.insert(QLatin1String("fileName"), fileName); + + Backend* backend = new Backend; + backend->metaData = backendMetaData; + backend->interface = 0; + backend->interfaceObject = 0; + backend->loader = 0; + addBackend(backend); +} + +bool QtIVIServiceManagerPrivate::registerBackend(QObject *serviceBackendInterface, const QStringList &interfaces) +{ + if (interfaces.isEmpty()) { + return false; + } + + // Verify that the object implements the ServiceBackendInterface + QtIVIServiceInterface *interface = qobject_cast<QtIVIServiceInterface*>(serviceBackendInterface); + if (!interface) { + return false; + } + + QVariantMap metaData = QVariantMap(); + + metaData.insert(QLatin1String("interfaces"), interfaces); + + Backend *backend = new Backend; + backend->metaData = metaData; + backend->interface = interface; + backend->interfaceObject = serviceBackendInterface; + backend->loader = 0; + + addBackend(backend); + return true; +} + +void QtIVIServiceManagerPrivate::unloadAllBackends() +{ + Q_Q(QtIVIServiceManager); + + q->beginResetModel(); + for(int i=0; i<m_backends.count(); i++) { + Backend* backend = m_backends.takeAt(i); + + //If the Interface is from a Plugin, the Plugin owns it and it will be deleted when unloading. + //Otherwise we own the Interface and delete the Pointer. + if (backend->loader) { + backend->loader->unload(); + delete backend->loader; + } else if (backend->interfaceObject) { + delete backend->interfaceObject; + } + + delete backend; + } + m_backends.clear(); + q->endResetModel(); +} + +void QtIVIServiceManagerPrivate::addBackend(Backend *backend) +{ + Q_Q(QtIVIServiceManager); + + q->beginInsertRows(QModelIndex(), m_backends.count(), m_backends.count()); + m_backends.append(backend); + q->endInsertRows(); + + foreach (const QString &interface, backend->metaData[QLatin1String("interfaces")].toStringList()) { + m_interfaceNames.insert(interface); + } +} + +QtIVIServiceInterface *QtIVIServiceManagerPrivate::loadServiceBackendInterface(struct Backend *backend) +{ + if (backend->interface) { + return backend->interface; + } + + QPluginLoader *loader = new QPluginLoader(backend->metaData[QLatin1String("fileName")].toString()); + QObject *plugin = loader->instance(); + if (plugin) { + + QtIVIServiceInterface *backendInterface = qobject_cast<QtIVIServiceInterface*>(plugin); + if (backendInterface) { + backend->interface = backendInterface; + backend->loader = loader; + return backend->interface; + } else { + qDebug("ServiceManager::serviceObjects - failed to cast to interface from '%s'", qPrintable(loader->fileName())); + } + + } else { + qDebug("ServiceManager::serviceObjects - failed to load '%s'", qPrintable(loader->fileName())); + } + + //Only delete the Loader right away if we didn't succeeded with loading the interfaces. + delete loader; + + return 0; +} + +/*! + * \class QtIVIServiceManager + * \inmodule QtIVICore + * \brief QtIVIServiceManager provides the Backends to QtIVIAbstractFeature + * + * QtIVIServiceManager is the heart of QtIVI and provides you a easy way to detect what + * Backends and interfaces are available. + * + * By default QtIVIServiceManager reads the metaData of all plugins within the "qtivi" folder + * of your plugin path. The plugin itself will be loaded once it's explictly requested by + * the developer by using findServiceByInterface() + * + * The registerService() function can be used to add Backend classes without putting them into + * a plugin. + * + * The service manager is a process wide singleton and can be accessed through the \l instance method. + */ +QtIVIServiceManager::QtIVIServiceManager() + : QAbstractListModel(0) + , d_ptr(new QtIVIServiceManagerPrivate(this)) +{ + d_ptr->searchPlugins(); +} + +/*! + * Returns the global service manager instance. + */ +QtIVIServiceManager *QtIVIServiceManager::instance() +{ + static QtIVIServiceManager* instance = new QtIVIServiceManager(); + return instance; +} + +/*! + * Destructor. + */ +QtIVIServiceManager::~QtIVIServiceManager() +{ + +} + +/*! + * Returns a List of Backends which implementing the specified \a interface. + */ +QList<QtIVIServiceObject *> QtIVIServiceManager::findServiceByInterface(const QString &interface) +{ + Q_D(QtIVIServiceManager); + return d->findServiceByInterface(interface); +} + +/*! + * Register a backend. The provided \a serviceBackendInterface must implement the QtIVIServiceInterface else + * the registration will fail. \a interfaces is list with interfaces which the backend handles. At least one + * interface is required. + * + * Returns true if the backend was successfully registered else false. + * + * \sa QtIVIServiceInterface + */ +bool QtIVIServiceManager::registerService(QObject *serviceBackendInterface, const QStringList &interfaces) +{ + Q_D(QtIVIServiceManager); + return d->registerBackend(serviceBackendInterface, interfaces); +} + +/*! + * \internal + * + * Unloads all currently loaded backends. Commonly only used for unit testing. + */ +void QtIVIServiceManager::unloadAllBackends() +{ + Q_D(QtIVIServiceManager); + return d->unloadAllBackends(); +} + +/*! + * Returns true if the specified \a interface has been registered. + */ +bool QtIVIServiceManager::hasInterface(const QString &interface) const +{ + Q_D(const QtIVIServiceManager); + return d->m_interfaceNames.contains(interface); +} + +/*! + * Returns the number of rows for the given \a parent. Typically \a parent is an empty model index. + * + * \sa QAbstractListModel::data() + */ +int QtIVIServiceManager::rowCount(const QModelIndex &parent) const +{ + Q_D(const QtIVIServiceManager); + return parent.isValid() ? 0 : d->m_backends.count(); +} + +/*! + * Returns the data for \a index and \a role. + * + * \sa QAbstractListModel::data() + */ +QVariant QtIVIServiceManager::data(const QModelIndex &index, int role) const +{ + Q_D(const QtIVIServiceManager); + + if (!index.isValid()) + return QVariant(); + + int row = index.row(); + + if (row >= 0 && row < d->m_backends.count() && role == Qt::DisplayRole) { + return QVariant::fromValue<QtIVIServiceInterface*>(d->m_backends.at(index.row())->interface); + } + + return QVariant(); +} diff --git a/src/ivicore/qtiviservicemanager.h b/src/ivicore/qtiviservicemanager.h new file mode 100644 index 0000000..1d591ad --- /dev/null +++ b/src/ivicore/qtiviservicemanager.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIVISERVICEMANAGER_H +#define QTIVISERVICEMANAGER_H + +#include <QtCore/QAbstractListModel> + +#include <QtIVICore/qtiviglobal.h> + +class QtIVIServiceObject; +class QtIVIServiceManagerPrivate; + +//TODO Detect simulation plugins +//TODO make it possible to only search there e.g. by a SearchFlag BitField +class Q_QTIVICORE_EXPORT QtIVIServiceManager : public QAbstractListModel +{ + Q_OBJECT +public: + static QtIVIServiceManager *instance(); + virtual ~QtIVIServiceManager(); + + QList<QtIVIServiceObject*> findServiceByInterface(const QString &interface); + bool hasInterface(const QString &interface) const; + + bool registerService(QObject *serviceBackendInterface, const QStringList &interfaces); + void unloadAllBackends(); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; +signals: + +private: + explicit QtIVIServiceManager(); + QtIVIServiceManagerPrivate * const d_ptr; + Q_DECLARE_PRIVATE(QtIVIServiceManager) +}; + +#endif // QTIVISERVICEMANAGER_H diff --git a/src/ivicore/qtiviservicemanager_p.h b/src/ivicore/qtiviservicemanager_p.h new file mode 100644 index 0000000..4077fbf --- /dev/null +++ b/src/ivicore/qtiviservicemanager_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIVISERVICEMANAGER_P_H +#define QTIVISERVICEMANAGER_P_H + +#include <QAbstractListModel> +#include <QVariantMap> +#include <QStringList> +#include <QMap> + +class QPluginLoader; +class QtIVIServiceInterface; +class QtIVIServiceObject; +class QtIVIServiceManager; + +struct Backend{ + QVariantMap metaData; + QtIVIServiceInterface *interface; + QObject *interfaceObject; + QPluginLoader *loader; +}; + +class QtIVIServiceManagerPrivate : public QObject +{ + Q_OBJECT + +public: + explicit QtIVIServiceManagerPrivate(QtIVIServiceManager *parent); + + QList<QtIVIServiceObject*> findServiceByInterface(const QString &interface); + + void searchPlugins(); + void registerBackend(const QString fileName, const QJsonObject metaData); + bool registerBackend(QObject *serviceBackendInterface, const QStringList &interfaces); + void addBackend(struct Backend *backend); + + void unloadAllBackends(); + + QtIVIServiceInterface *loadServiceBackendInterface(struct Backend *backend); + + QList<Backend*> m_backends; + QSet<QString> m_interfaceNames; + + + QtIVIServiceManager * const q_ptr; + Q_DECLARE_PUBLIC(QtIVIServiceManager) + +signals: + void beginInsertRows(const QModelIndex &index, int start, int end); + void endInsertRows(); + +}; + +#endif // QTIVISERVICEMANAGER_P_H + diff --git a/src/ivicore/qtiviserviceobject.cpp b/src/ivicore/qtiviserviceobject.cpp new file mode 100644 index 0000000..1a2dc07 --- /dev/null +++ b/src/ivicore/qtiviserviceobject.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtiviserviceobject.h" + +#include <QUuid> + +/*! + * \class QtIVIServiceObject + * \inmodule QtIVICore + * \brief QtIVIServiceObject is the connection point to a Backend Service + * + * QtIVIServiceObject provides you with a list of interfaces the Backend implements. + * + * By using interfaceInstance() a QObject implementing this interface will be returned. + * The returned interface can contain signals which needs to be connected to by the Feature + * implementing this interface. + * + * \sa QtIVIAbstractFeature + */ + +/*! + * \property QtIVIServiceObject::id + * \brief A unique ID for the service object instance. + * + * Each service object has a unique ID. When sub-classing, the \l QtIVIServiceObject::id() + * function can be overloaded to control how the ID is generad. + */ + +/*! + * Constructor. + * + * \a parent is passed on to \l QObject. + */ +QtIVIServiceObject::QtIVIServiceObject(QObject *parent) + : QObject(parent) +{ + +} + +/*! + * Destructor. + */ +QtIVIServiceObject::~QtIVIServiceObject() +{ + +} + +/*! + * The id() function can be overloaded to control the generation of + * the unique ID used by this Object. + * + * By default QUuid::createUuid() is used. + */ +QString QtIVIServiceObject::id() const +{ + static QUuid id = QUuid::createUuid(); + return id.toString(); +} + +/*! + * \class QtIVIServiceInterface + * \inmodule QtIVICore + * \brief Interface class for services + * + * The QtIVIServiceInterface class defines the interface of services registered at the QtIVIServiceManager. + * + * Commonly, service objects inherit the concrete class QtIVIServiceObject instead of using QtIVIServiceInterface directly. + * + * \sa QtIVIServiceObject + */ + +/*! + * \fn QStringList QtIVIServiceInterface::interfaces() const + * \inmodule QtIVICore + * + * Returns a list of service interface names supported by the service object instance. + */ + +/*! + * \fn QObject* QtIVIServiceInterface::interfaceInstance(const QString& interface) const + * \inmodule QtIVICore + * + * Returns an object implementing the service interface requested through \a interface. + */ diff --git a/src/ivicore/qtiviserviceobject.h b/src/ivicore/qtiviserviceobject.h new file mode 100644 index 0000000..31a5798 --- /dev/null +++ b/src/ivicore/qtiviserviceobject.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIVISERVICEOBJECT_H +#define QTIVISERVICEOBJECT_H + +#include <QObject> + +#include <QtIVICore/QtIVIServiceInterface> +#include <QtIVICore/qtiviglobal.h> + +class Q_QTIVICORE_EXPORT QtIVIServiceObject : public QObject, public QtIVIServiceInterface +{ + Q_OBJECT + Q_INTERFACES(QtIVIServiceInterface) + + Q_PROPERTY(QString id READ id CONSTANT) + +public: + explicit QtIVIServiceObject(QObject *parent = 0); + virtual ~QtIVIServiceObject(); + + virtual QString id() const; + +private: +}; + +#endif // QTIVISERVICEOBJECT_H diff --git a/src/ivicore/qtivizonesattached.cpp b/src/ivicore/qtivizonesattached.cpp new file mode 100644 index 0000000..30deb44 --- /dev/null +++ b/src/ivicore/qtivizonesattached.cpp @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtivizonesattached.h" + +#include <QtCore/private/qmetaobjectbuilder_p.h> + +#include <qtiviabstractzonemodelfeature.h> + +QtIVIZonesAttached::QtIVIZonesAttached(QObject *parent) : QObject(parent) +{ + m_item = qobject_cast<QtIVIAbstractZoneModelFeature*>(parent); + if (m_item && m_item->model()) + { + m_item->startAutoDiscovery(); // TODO we probably do not want this here, as it is a potentially costly, blocking, call + + // Ensure that the model does not change + connect(m_item->model(), &QAbstractItemModel::layoutChanged, this, &QtIVIZonesAttached::onModelChanged); + connect(m_item->model(), &QAbstractItemModel::rowsInserted, this, &QtIVIZonesAttached::onModelChanged); + connect(m_item->model(), &QAbstractItemModel::rowsRemoved, this, &QtIVIZonesAttached::onModelChanged); + connect(m_item->model(), &QAbstractItemModel::dataChanged, this, &QtIVIZonesAttached::onModelChanged); + connect(m_item->model(), &QAbstractItemModel::modelReset, this, &QtIVIZonesAttached::onModelChanged); + } + else + qWarning() << "Could not attach Zones property to :" << parent << " is not a QtIVIAbstractZoneModelFeature"; + + m_metaObject = buildMetaObject(m_item); +} + +QtIVIZonesAttached::~QtIVIZonesAttached() +{ + free(m_metaObject); + m_metaObject = 0; +} + +QtIVIZonesAttached *QtIVIZonesAttached::qmlAttachedProperties(QObject *object) +{ + return new QtIVIZonesAttached(object); +} + +void QtIVIZonesAttached::onModelChanged() +{ + qWarning() << "Attached Zones property does not support dynamically modifying models."; +} + +QMetaObject *QtIVIZonesAttached::buildMetaObject(QtIVIAbstractZoneModelFeature *zoneModel) +{ + QMetaObjectBuilder builder; + + builder.setSuperClass(&QObject::staticMetaObject); + builder.setClassName("QtIVIZonesAttached"); + builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + + QRegExp reProperty(QStringLiteral("^[a-z_][A-Za-z0-9_]*$")); + + if (zoneModel && zoneModel->model()) { + int j = 0; + QStringList names; + for(int i=0; i<zoneModel->model()->rowCount(); ++i) + { + QModelIndex index = zoneModel->model()->index(i, 0); + QString name = index.data(Qt::DisplayRole).toString(); + + // Ensure that name is a valid, unique property name + if (reProperty.indexIn(name) == -1 || names.contains(name)) + while (names.contains(name)) + name = QStringLiteral("zone%1").arg(j++); + + QMetaPropertyBuilder pbuilder = builder.addProperty(name.toUtf8(), "QObject*", i); + pbuilder.setReadable(true); + pbuilder.setWritable(false); + pbuilder.setConstant(true); + + names << name; + } + } + + return builder.toMetaObject(); +} + +const QMetaObject *QtIVIZonesAttached::metaObject() const { return m_metaObject; } + +int QtIVIZonesAttached::qt_metacall(QMetaObject::Call c, int _id, void **argv) +{ + int id = QObject::qt_metacall(c, _id, argv); + if (id < 0) + return id; + + switch(c) + { + case QMetaObject::ReadProperty: + if (id < m_item->model()->rowCount()) + { + QObject *object = m_item->model()->index(id, 0).data(Qt::UserRole).value<QObject*>(); + QMetaType::construct(QMetaType::QObjectStar, argv[0], &object); + return -1; + } + else + return id-m_item->model()->rowCount(); + + default: // We only support read-only properties + break; + } + + return qt_metacall_generated(c, _id, argv); +} + + + + +// Start of moc generated code + +#include <QtCore/qbytearray.h> +#include <QtCore/qmetatype.h> +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'qtivizonesattached.h' doesn't include <QObject>." +#elif Q_MOC_OUTPUT_REVISION != 67 +#error "This file was generated using the moc from 5.5.0. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +struct qt_meta_stringdata_QtIVIZonesAttached_t { + QByteArrayData data[3]; + char stringdata0[35]; +}; +#define QT_MOC_LITERAL(idx, ofs, len) \ + Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ + qptrdiff(offsetof(qt_meta_stringdata_QtIVIZonesAttached_t, stringdata0) + ofs \ + - idx * sizeof(QByteArrayData)) \ + ) +static const qt_meta_stringdata_QtIVIZonesAttached_t qt_meta_stringdata_QtIVIZonesAttached = { + { +QT_MOC_LITERAL(0, 0, 18), // "QtIVIZonesAttached" +QT_MOC_LITERAL(1, 19, 14), // "onModelChanged" +QT_MOC_LITERAL(2, 34, 0) // "" + + }, + "QtIVIZonesAttached\0onModelChanged\0" +}; +#undef QT_MOC_LITERAL + +static const uint qt_meta_data_QtIVIZonesAttached[] = { + + // content: + 7, // revision + 0, // classname + 0, 0, // classinfo + 1, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + // slots: name, argc, parameters, tag, flags + 1, 0, 19, 2, 0x08 /* Private */, + + // slots: parameters + QMetaType::Void, + + 0 // eod +}; + +void QtIVIZonesAttached::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + QtIVIZonesAttached *_t = static_cast<QtIVIZonesAttached *>(_o); + Q_UNUSED(_t) + switch (_id) { + case 0: _t->onModelChanged(); break; + default: ; + } + } + Q_UNUSED(_a); +} + +const QMetaObject QtIVIZonesAttached::staticMetaObject = { + { &QObject::staticMetaObject, qt_meta_stringdata_QtIVIZonesAttached.data, + qt_meta_data_QtIVIZonesAttached, qt_static_metacall, Q_NULLPTR, Q_NULLPTR} +}; + +void *QtIVIZonesAttached::qt_metacast(const char *_clname) +{ + if (!_clname) return Q_NULLPTR; + if (!strcmp(_clname, qt_meta_stringdata_QtIVIZonesAttached.stringdata0)) + return static_cast<void*>(const_cast< QtIVIZonesAttached*>(this)); + return QObject::qt_metacast(_clname); +} + +// This method name has been extended with the postfix "_generated" to allow us to reimplement it +int QtIVIZonesAttached::qt_metacall_generated(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { + if (_id < 1) + *reinterpret_cast<int*>(_a[0]) = -1; + _id -= 1; + } + return _id; +} +QT_END_MOC_NAMESPACE + +// End of moc-generated code diff --git a/src/ivicore/qtivizonesattached.h b/src/ivicore/qtivizonesattached.h new file mode 100644 index 0000000..2f01abc --- /dev/null +++ b/src/ivicore/qtivizonesattached.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIVIZONESATTACHED_H +#define QTIVIZONESATTACHED_H + +#include <QObject> +#include <QtQml> + +#include <QtIVICore/qtiviglobal.h> + +class QtIVIAbstractZoneModelFeature; + +class Q_QTIVICORE_EXPORT QtIVIZonesAttached : public QObject +{ +// Start of Q_OBJECT macro +public: + Q_OBJECT_CHECK + static const QMetaObject staticMetaObject; + virtual const QMetaObject *metaObject() const; + virtual void *qt_metacast(const char *); + virtual int qt_metacall(QMetaObject::Call, int, void **); + QT_TR_FUNCTIONS +private: \ + Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); + struct QPrivateSignal {}; +// End of Q_OBJECT macro + virtual int qt_metacall_generated(QMetaObject::Call, int, void **); + +public: + explicit QtIVIZonesAttached(QObject *parent = 0); + ~QtIVIZonesAttached(); + + static QtIVIZonesAttached *qmlAttachedProperties(QObject*); + +private slots: + void onModelChanged(); + +private: + QMetaObject *buildMetaObject(QtIVIAbstractZoneModelFeature*); + + QtIVIAbstractZoneModelFeature *m_item; + + QMetaObject *m_metaObject; +}; + +QML_DECLARE_TYPEINFO(QtIVIZonesAttached, QML_HAS_ATTACHED_PROPERTIES) + +#endif // QTIVIZONESATTACHED_H diff --git a/src/ivivehiclefunctions/doc/qtivivehiclefunctions.qdocconf b/src/ivivehiclefunctions/doc/qtivivehiclefunctions.qdocconf new file mode 100644 index 0000000..5a41ee4 --- /dev/null +++ b/src/ivivehiclefunctions/doc/qtivivehiclefunctions.qdocconf @@ -0,0 +1,52 @@ +include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) + +project = QtIVIVehicleFunctions +description = Qt IVI Vehicle Functions Reference Documentation +version = $QT_VERSION + + + +qhp.projects = QtIVIVehicleFunctions + +qhp.QtIVIVehicleFunctions.file = qtivivehiclefunctions.qhp +qhp.QtIVIVehicleFunctions.namespace = org.qt-project.qtivicore.$QT_VERSION_TAG +qhp.QtIVIVehicleFunctions.virtualFolder = qtivivehiclefunctions +qhp.QtIVIVehicleFunctions.indexTitle = Qt IVI Vehicle Functions +qhp.QtIVIVehicleFunctions.indexRoot = + +qhp.QtIVIVehicleFunctions.filterAttributes = qtivivehiclefunctions $QT_VERSION qtrefdoc +qhp.QtIVIVehicleFunctions.customFilters.Qt.name = QtIVIVehicleFunctions $QT_VERSION +qhp.QtIVIVehicleFunctions.customFilters.Qt.filterAttributes = qtIVIVehicleFunctions $QT_VERSION +qhp.QtIVIVehicleFunctions.subprojects = overviews classes qml examples +qhp.QtIVIVehicleFunctions.subprojects.classes.title = C++ Classes +qhp.QtIVIVehicleFunctions.subprojects.classes.indexTitle = Qt IVI Vehicle Functions C++ Classes +qhp.QtIVIVehicleFunctions.subprojects.classes.selectors = class fake:headerfile +qhp.QtIVIVehicleFunctions.subprojects.classes.sortPages = true +qhp.QtIVIVehicleFunctions.subprojects.qml.title = QML Types +qhp.QtIVIVehicleFunctions.subprojects.qml.indexTitle = Qt IVI Vehicle Functions QML Types +qhp.QtIVIVehicleFunctions.subprojects.qml.selectors = fake:headerfile +qhp.QtIVIVehicleFunctions.subprojects.qml.sortPages = true +qhp.QtIVIVehicleFunctions.subprojects.overviews.title = Overviews +qhp.QtIVIVehicleFunctions.subprojects.overviews.indexTitle = Qt IVI Vehicle Functions Overview +qhp.QtIVIVehicleFunctions.subprojects.overviews.selectors = fake:page,group,module +qhp.QtIVIVehicleFunctions.subprojects.examples.title = Qt IVI Vehicle Functions Examples +qhp.QtIVIVehicleFunctions.subprojects.examples.indexTitle = Qt IVI Vehicle Functions Examples +qhp.QtIVIVehicleFunctions.subprojects.examples.selectors = fake:example + +tagfile = ../../../doc/qtivivehiclefunctions/qtivivehiclefunctions.tags + +depends += qtcore qtdoc qtquick qtqml qtivicore + +headerdirs += .. \ + ../../imports/vehiclefunctions + +sourcedirs += .. \ + ../../imports/vehiclefunctions \ + +examplesinstallpath = qtivivehiclefunctions + +#imagedirs += images + +navigation.landingpage = "Qt IVI Vehicle Functions" +navigation.cppclassespage = "Qt IVI Vehicle Functions C++ Classes" +navigation.qmltypespage = "Qt IVI Vehicle Functions QML Types" diff --git a/src/ivivehiclefunctions/ivivehiclefunctions.pro b/src/ivivehiclefunctions/ivivehiclefunctions.pro new file mode 100644 index 0000000..19979fa --- /dev/null +++ b/src/ivivehiclefunctions/ivivehiclefunctions.pro @@ -0,0 +1,18 @@ +TARGET = QtIVIVehicleFunctions +QT = core qml ivicore +CONFIG += c++11 +VERSION = 1.0.0 + +QMAKE_DOCS = $$PWD/doc/qtivivehiclefunctions.qdocconf + +CMAKE_MODULE_TESTS = '-' + +HEADERS += \ + qtiviclimatecontrol.h \ + qtiviclimatecontrolbackendinterface.h \ + qtivivehiclefunctionsglobal.h + +SOURCES += \ + qtiviclimatecontrol.cpp + +load(qt_module) diff --git a/src/ivivehiclefunctions/qtiviclimatecontrol.cpp b/src/ivivehiclefunctions/qtiviclimatecontrol.cpp new file mode 100644 index 0000000..19931f1 --- /dev/null +++ b/src/ivivehiclefunctions/qtiviclimatecontrol.cpp @@ -0,0 +1,819 @@ +#include "qtiviclimatecontrol.h" + +#include "qtiviclimatecontrolbackendinterface.h" + +/*! + * \class QtIVIClimateControlBackendInterface + * + * \brief The QtIVIClimateControlBackendInterface defines the interface for backends to the + * QtIVIClimateControl and QtIVIClimateZone feature classes. + * + * \ingroup backends + * \inmodule QtIVIVehicleFunctions + * + * The QtIVIClimateControlBackendInterface is the interface used by \l QtIVIClimateControl and + * \l QtIVIClimateZone. + * + * The interface is discovered by a \l QtIVIClimateControl object, which connects to it and sets up + * the connections to a set of \l QtIVIClimateZone. + * + * For ranged properties (see the documentation of the \l QtIVIClimateControl and \l QtIVIClimateZone), + * the backend is expected to check the range of the input values. + * + * \sa QtIVIClimateControl, QtIVIClimateZone + */ + +/*! + * \fn QtIVIClimateControlBackendInterface::QtIVIClimateControlBackendInterface(QObject *parent=0) + * + * Constructs a backend interface. + * + * The \a parent is sent to the QObject constructor. + */ + +/*! + * \fn QStringList QtIVIClimateControlBackendInterface::zones() const + * + * Returns a list of supported zone names. + * + * The returned names must be valid QML property names, i.e. \c {[a-z_][A-Za-z0-9_]*}. + */ + +/*! + * \fn QtIVIClimateZone::OptionalFeatures QtIVIClimateControlBackendInterface::zoneFeatures(const QString &zone) const + * + * Returns a bitfield with the supported features for a given \a zone. + */ + +/*! + * \fn QtIVIClimateControl::OptionalFeatures QtIVIClimateControlBackendInterface::climateFeatures() const + * + * Returns a bitfield with the supported features of the climate control. + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::setTargetTemperature(const QString &zone, int value) + * + * Sets the target temperature of \a zone to \a value, wheret he \a value is expressed in + * centigrades and may be range limited by the backend. + * + * This method is expected to emit a \l targetTemperatureChanged() signal when receiving a new + * \a value. The signal is expected to be emitted if the given \a value is out of range and no + * actual change takes place. + * + * \sa targetTemperature(), targetTemperatureChanged() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::setSeatCooler(const QString &zone, int value) + * + * Sets the seat ventilation level of \a zone to \a value, where \a value can be \c 0 (off) or + * between \c 1 (least cool) to \c 10 (coolest). + * + * This method is expected to emit a \l seatCoolerChanged() signal when receiving a new + * \a value. The signal is expected to be emitted if the given \a value is out of range and no + * actual change takes place. + * + * \sa seatCooler(), seatCoolerChanged() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::setSeatHeater(const QString &zone, int value) + * + * Sets the seat heater level of \a zone to \a value, where \a value can be \c 0 (off) or between + * \c 1 (least warm) to \c 10 (warmest). + * + * This method is expected to emit a \l seatHeaterChanged() signal when receiving a new + * \a value. The signal is expected to be emitted if the given \a value is out of range and no + * actual change takes place. + * + * \sa seatHeater(), seatHeaterChanged() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::setAirflowDirection(QtIVIClimateControl::AirflowDirection airflowDirection) + * + * Sets the air flow direction to \a airflowDirection. + * + * This method is expected to emit the \l airflowDirectionChanged() signal when receiving a + * new \a airflowDirection. + * + * \sa airflowDirection(), airflowDirectionChanged() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::setAirConditioningEnabled(bool enabled) + * + * Enables or disables the air conditioning based on \a enabled. + * + * This method is expected to emit the \l airConditioningEnabledChanged() signal when receiving a + * new \a enabled. + * + * \sa airConditioningEnabled(), airConditioningEnabledChanged() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::setHeaterEnabled(bool enabled) + * + * Enables or disables the heater based on \a enabled. + * + * This method is expected to emit the \l heaterEnabledChanged() signal when receiving a + * new \a enabled. + * + * \sa heaterEnabled(), heaterEnabledChanged() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::setAirRecirculationEnabled(bool enabled) + * + * Enables or disables the air recirculation based on \a enabled. + * + * This method is expected to emit the \l airRecirculationEnabledChanged() signal when receiving a + * new \a enabled. + * + * \sa airRecirculationEnabled(), airRecirculationEnabledChanged() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::setSteeringWheelHeater(const QString &zone, int value) + * + * Sets the steering wheel heater level of \a zone to \a value, where \a value can be \c 0 (off) + * or between \c 1 (least warm) to \c 10 (warmest). + * + * This method is expected to emit a \l steeringWheelHeaterChanged() signal when receiving a new + * \a value. The signal is expected to be emitted if the given \a value is out of range and no + * actual change takes place. + * + * \sa steeringWheelHeater(), steeringWheelHeaterChanged() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::setFanSpeedLevel(const QString &zone, int value) + * + * Sets the fan speed level of \a zone to \a value, where \a value can be \c 0 (off) or between + * \c 1 (weakest) to \c 10 (strongest). + * + * This method is expected to emit a \l fanSpeedLevelChanged() signal when receiving a new + * \a value. The signal is expected to be emitted if the given \a value is out of range and no + * actual change takes place. + * + * \sa fanSpeedLevel(), fanSpeedLevelChanged() + */ + +/*! + * \fn int QtIVIClimateControlBackendInterface::targetTemperature(const QString &zone) const + * + * Returns the target temperature in centigrades for \a zone. + * + * \sa setTargetTemperature(), targetTemperatureChanged() + */ + +/*! + * \fn int QtIVIClimateControlBackendInterface::seatCooler(const QString &zone) const + * + * Returns the seat ventilation level for \a zone, where the level can be \c 0 (off) or + * between \c 1 (least cool) to \c 10 (coolest). + * + * \sa setSeatCooler(), seatCoolerChanged() + */ + +/*! + * \fn int QtIVIClimateControlBackendInterface::seatHeater(const QString &zone) const + * + * Returns the seat heater level for \a zone, where the level can be \c 0 (off) or between + * \c 1 (least warm) to \c 10 (warmest). + * + * \sa setSeatHeater(), seatHeaterChanged() + */ + +/*! + * \fn QtIVIClimateControl::AirflowDirection QtIVIClimateControlBackendInterface::airflowDirection() const + * + * Returns the airflow direction. + * + * \sa setAirflowDirection(), airflowDirectionChanged() + */ + +/*! + * \fn bool QtIVIClimateControlBackendInterface::airConditioningEnabled() const + * + * Returns \c true if the air conditioning is enabled, otherwise \c false. + * + * \sa setAirConditioningEnabled(), airConditioningEnabledChanged() + */ + +/*! + * \fn bool QtIVIClimateControlBackendInterface::heaterEnabled() const + * + * Returns \c true if the air conditioning is enabled, otherwise \c false. + * + * \sa setHeaterEnabled(), heaterEnabledChanged() + */ + +/*! + * \fn bool QtIVIClimateControlBackendInterface::airRecirculationEnabled() const + * + * Returns \c true if the air conditioning is enabled, otherwise \c false. + * + * \sa setAirRecirculationEnabled(), airRecirculationEnabledChanged() + */ + +/*! + * \fn int QtIVIClimateControlBackendInterface::steeringWheelHeater(const QString &zone) const + * + * Returns the steering wheel heater level of \a zone, where the level can be \c 0 (off) or between + * \c 1 (least warm) to \c 10 (warmest). + * + * \sa setSteeringWheelHeater(), steeringWheelHeaterChanged() + */ + +/*! + * \fn int QtIVIClimateControlBackendInterface::fanSpeedLevel(const QString &zone) const + * + * Returns the fan speed level of \a zone, where the level can be \c 0 (off) or between + * \c 1 (weakest) to \c 10 (strongest). + * + * \sa setFanSpeedLevel(), fanSpeedLevelChanged() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::targetTemperatureChanged(const QString &zone, int value) + * + * The signal is emitted when the target temperature for \a zone is changed to \a value, where + * value is expressed in centigrades. + * + * \sa targetTemperature(), setTargetTemperature() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::seatCoolerChanged(const QString &zone, int value) + * + * The signal is emitted when the seat cooler level is changed for \a zone to \a value, where the + * \a value can be \c 0 (off) or between \c 1 (least cool) to \c 10 (coolest). + * + * \sa seatCooler(), setSeatCooler() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::seatHeaterChanged(const QString &zone, int value) + * + * The signal is emitted when the seat cooler level is changed for \a zone to \a value, where the + * \a value can be \c 0 (off) or between \c 1 (least warm) to \c 10 (warmest). + * + * \sa seatHeater(), setSeatHeater() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::airflowDirectionChanged(QtIVIClimateControl::AirflowDirection airflowDirection) + * + * The signal is emitted when the airflow direction is changed to \a airflowDirection. + * + * \sa airflowDirection(), setAirflowDirection() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::airConditioningEnabledChanged(bool enabled) + * + * The signal is emitted when the air conditioning state is changed to \a enabled. + * + * \sa airConditioningEnabled(), setAirConditioningEnabled() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::heaterEnabledChanged(bool enabled) + * + * The signal is emitted whent he heater state is changed to \a enabled. + * + * \sa heaterEnabled(), setHeaterEnabled() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::airRecirculationEnabledChanged(bool enabled) + * + * The signal is emitted when the air recirculation state is changed to \a enabled. + * + * \sa airRecirculationEnabled(), setAirRecirculationEnabled() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::steeringWheelHeaterChanged(const QString &zone, int level) + * + * The signals ie emitted when the steering wheel heater level of \a zone is changed to \a level, where the + * \a level can be \c 0 (off) or between \c 1 (least warm) to \c 10 (warmest). + * + * \sa steeringWheelHeater(), setSteeringWheelHeater() + */ + +/*! + * \fn void QtIVIClimateControlBackendInterface::fanSpeedLevelChanged(const QString &zone, int level) + * + * The signals ie emitted when the fan speel level of \a zone is changed to \a level, where the \a level + * can be \c 0 (off) or between \c 1 (weakest) to \c 10 (strongest). + * + * \sa fanSpeedLevel(), setFanSpeedLevel() + */ + + +QString QtIVIClimateControlBackendInterface::interfaceName = QLatin1String("com.pelagicore.ClimateControl"); + + + +/*! + * \class QtIVIClimateZone + * + * \brief Provides an interface to zone specific properties of climate control. + * + * \ingroup features + * \inmodule QtIVIVehicleFunctions + * + * \sa QtIVIClimateControl + */ + +/*! + * \enum QtIVIClimateZone::OptionalFeature + * + * This enum specifies what optional features are available in a given zone: + * + * \value HasTargetTemperature + * The zone supports controlling the target temperature. + * \value HasSeatCooler + * The zone has a seat cooler. + * \value HasSeatHeater + * The zone has a seat heater. + * \value HasSteeringWheelHeater + * The zone has steering wheel heater. + * \value HasFanSpeed + * The zone can control fan speed. + * + * \omitvalue None + */ + +QtIVIClimateZone::QtIVIClimateZone(const QString &zone, QtIVIClimateControl *parent, QtIVIClimateControlBackendInterface *backend) + : QObject(parent) + , m_zone(zone) + , m_targetTemperature(0) + , m_seatCooler(0) + , m_seatHeater(0) + , m_steeringWheelHeater(0) + , m_fanSpeedLevel(0) + , m_features(QtIVIClimateZone::None) +{ + connect(backend, &QtIVIClimateControlBackendInterface::targetTemperatureChanged, this, &QtIVIClimateZone::onTargetTemperatureChanged); + connect(backend, &QtIVIClimateControlBackendInterface::seatCoolerChanged, this, &QtIVIClimateZone::onSeatCoolerChanged); + connect(backend, &QtIVIClimateControlBackendInterface::seatHeaterChanged, this, &QtIVIClimateZone::onSeatHeaterChanged); + connect(backend, &QtIVIClimateControlBackendInterface::steeringWheelHeaterChanged, this, &QtIVIClimateZone::onSteeringWheelHeaterChanged); + connect(backend, &QtIVIClimateControlBackendInterface::fanSpeedLevelChanged, this, &QtIVIClimateZone::onFanSpeedLevelChanged); + + onTargetTemperatureChanged(zone, backend->targetTemperature(zone)); + onSeatCoolerChanged(zone, backend->seatCooler(zone)); + onSeatHeaterChanged(zone, backend->seatHeater(zone)); + onSteeringWheelHeaterChanged(zone, backend->steeringWheelHeater(zone)); + onFanSpeedLevelChanged(zone, backend->fanSpeedLevel(zone)); + + /* Set the has properties last to ensure that the value is available when signalling */ + m_features = backend->zoneFeatures(zone); +} + +/*! + * Returns \c true if a given feature, \a f, is supported by the zone. + */ +bool QtIVIClimateZone::hasFeature(QtIVIClimateZone::OptionalFeature f) const +{ + return m_features.testFlag(f); +} + +/*! + * \property QtIVIClimateZone::zone + * \brief The current zone. + * + * The zone of the object. Can be used to determine where in the vehicle the zone is located. + */ +QString QtIVIClimateZone::zone() const +{ + return m_zone; +} + +/*! + * \property QtIVIClimateZone::targetTemperature + * \brief The target temperature of the zone. + * + * The target temperature of the zone expressed in centigrades. + */ +int QtIVIClimateZone::targetTemperature() const +{ + if (hasFeature(HasTargetTemperature)) + return m_targetTemperature; + else + return 0; +} + +void QtIVIClimateZone::setTargetTemperature(int t) +{ + if (hasFeature(HasTargetTemperature)) + qobject_cast<QtIVIClimateControl*>(parent())->backend()->setTargetTemperature(m_zone, t); + else + qWarning() << "Trying to set ClimateZone::targetTemperature in an unsupported zone or without a backend."; +} + +/*! + * \property QtIVIClimateZone::seatCooler + * \brief The seat cooler level of the zone. + * + * The seat cooler level of the zone, where the level can be \c 0 (off) or between \c 1 (least + * cool) to \c 10 (coolest). + */ +int QtIVIClimateZone::seatCooler() const +{ + if (hasFeature(HasSeatCooler)) + return m_seatCooler; + else + return 0; +} + +void QtIVIClimateZone::setSeatCooler(int t) +{ + if (t < 0 || t > 10) { + qWarning() << "Trying to set ClimateZone::seatCooler to " << t << " which is out of range (0-10)."; + return; + } + + if (hasFeature(HasSeatCooler)) + qobject_cast<QtIVIClimateControl*>(parent())->backend()->setSeatCooler(m_zone, t); + else + qWarning() << "Trying to set ClimateZone::seatCooler in an unsupported zone or without a backend."; +} + +/*! + * \property QtIVIClimateZone::seatHeater + * \brief The seat heater level of the zone. + * + * The seat heater level of the zone, where the level can be \c 0 (off) or between \c 1 (least + * warm) to \c 10 (warmest). + */ +int QtIVIClimateZone::seatHeater() const +{ + if (hasFeature(HasSeatHeater)) + return m_seatHeater; + else + return 0; +} + +void QtIVIClimateZone::setSeatHeater(int t) +{ + if (t < 0 || t > 10) { + qWarning() << "Trying to set ClimateZone::seatHeater to " << t << " which is out of range (0-10)."; + return; + } + + if (hasFeature(HasSeatHeater)) + qobject_cast<QtIVIClimateControl*>(parent())->backend()->setSeatHeater(m_zone, t); + else + qWarning() << "Trying to set ClimateZone::seatHeater in an unsupported zone or without a backend."; +} + +void QtIVIClimateZone::setSteeringWheelHeater(int t) +{ + if (hasFeature(HasSteeringWheelHeater)) + qobject_cast<QtIVIClimateControl*>(parent())->backend()->setSteeringWheelHeater(m_zone, t); +} + +void QtIVIClimateZone::setFanSpeedLevel(int fsl) +{ + if (hasFeature(HasFanSpeed)) + qobject_cast<QtIVIClimateControl*>(parent())->backend()->setFanSpeedLevel(m_zone, fsl); +} + + +void QtIVIClimateZone::onTargetTemperatureChanged(const QString &z, int t) +{ + if (z == m_zone) { + m_targetTemperature = t; + if (hasFeature(HasTargetTemperature)) + emit targetTemperatureChanged(m_targetTemperature); + } +} + +void QtIVIClimateZone::onSeatCoolerChanged(const QString &z, int t) +{ + if (z == m_zone) { + m_seatCooler = t; + if (hasFeature(HasSeatCooler)) + emit seatCoolerChanged(m_seatCooler); + } +} + +void QtIVIClimateZone::onSeatHeaterChanged(const QString &z, int t) +{ + if (z == m_zone) { + m_seatHeater = t; + if (hasFeature(HasSeatHeater)) + emit seatHeaterChanged(m_seatHeater); + } +} + +void QtIVIClimateZone::onSteeringWheelHeaterChanged(const QString &z, int steeringWheelHeater) +{ + if (z == m_zone) { + m_steeringWheelHeater = steeringWheelHeater; + if (hasFeature(HasSteeringWheelHeater)) + emit steeringWheelHeaterChanged(m_steeringWheelHeater); + } +} + +void QtIVIClimateZone::onFanSpeedLevelChanged(const QString &z, int fanSpeedLevel) +{ + if (z == m_zone) { + m_fanSpeedLevel = fanSpeedLevel; + if (hasFeature(HasFanSpeed)) + emit fanSpeedLevelChanged(m_fanSpeedLevel); + } +} + + +/*! + * \class QtIVIClimateControl + * \inmodule QtIVIClimateControl + * \brief Provides an interface to the climate control. + * + * The QtIVIClimateControl provides an interface to the climate control of the vehicle. + * + * The climate control properties are divided into two categories: central or zoned. The central + * properties are exposed directly through the QtIVIClimateControl while the zoned properties are + * exposed through \l QtIVIClimateZone objects. The zones are retreived using the \l zoneObject + * method. + * + * The QtIVIClimateControl expects a single backend to be available. It is recommended to use it + * with \l {QtIVIAbstractFeature::autoDiscovery} {autoDiscovery} enabled. + * + * \sa QtIVIClimateZone + */ + +/*! + * \enum QtIVIClimateControl::AirflowDirection + * \value FloorPanel + * Direct airflow along the floor panel. + * \value FloorDuct + * Direct airflow through the floor duct. + * \value BiLevel + * Direct airflow at both levels. + * \value DefrostFloor + * Direct airflow to defrost. + */ + +/*! + * \enum QtIVIClimateControl::OptionalFeature + * + * \value HasAirflowDirection + * The climate control supports airflow direction control. + * \value HasAirConditioning + * The climate control air conditioning can be enabled/disabled. + * \value HasHeater + * The climate control heater can be enabled/disabled. + * \value HasAirRecirculation + * The climate control air recirculation can be enabled/disabled. + * + * \omitvalue None + * + */ + +/*! + * \brief QtIVIClimateControl::QtIVIClimateControl + * Constructs a climate control object. + * + * The \a parent argument is passed on to the \l QtIVIAbstractFeature base class. + */ +QtIVIClimateControl::QtIVIClimateControl(QObject *parent) + : QtIVIAbstractZoneModelFeature(QtIVIClimateControlBackendInterface::interfaceName, true, parent) + , m_airflowDirection(QtIVIClimateControl::BiLevel) + , m_airConditioning(false) + , m_heater(false) + , m_airRecirculation(false) +{ +} + +/*! + * Returns a list of supported zone named. + */ +QStringList QtIVIClimateControl::zones() const +{ + return m_zones.keys(); +} + +/*! + * Returns an object instance for a given zone, \a z, or \c null if the zone is not supported. + * + * \sa climateZoneObject() + */ +QObject *QtIVIClimateControl::zoneObject(const QString &z) const +{ + return climateZoneObject(z); +} + +/*! + * Returns a QtIVIClimateZone object instance for a given zone, \a z, or \c null if the zone is not supported. + * + * \sa zoneObject() + */ +QtIVIClimateZone *QtIVIClimateControl::climateZoneObject(const QString &z) const +{ + if (m_zones.contains(z)) + return m_zones[z]; + + return 0; +} + +/*! + * Returns \c true if the given feature, \a f, is supported by the climate control. + */ +bool QtIVIClimateControl::hasFeature(QtIVIClimateControl::OptionalFeature f) const +{ + if (backend()) + return backend()->climateFeatures().testFlag(f); + else + return false; +} + +/*! + * \property QtIVIClimateControl::airflowDirection + * \brief The airflow direction. + * + * \sa QtIVIClimateControl::AirflowDirection + */ +QtIVIClimateControl::AirflowDirection QtIVIClimateControl::airflowDirection() const +{ + return m_airflowDirection; +} + +/*! + * \property QtIVIClimateControl::airConditioning + * \brief \c True if the air conditioning is enabled. + */ +bool QtIVIClimateControl::isAirConditioningEnabled() const +{ + return m_airConditioning; +} + +/*! + * \property QtIVIClimateControl::heater + * \brief \c True if the heater is enabled. + */ +bool QtIVIClimateControl::isHeaterEnabled() const +{ + return m_heater; +} + +/*! + * \property QtIVIClimateControl::airRecirculation + * \brief \c True if the air recirculation is enabled. + */ +bool QtIVIClimateControl::isAirRecirculationEnabled() const +{ + return m_airRecirculation; +} + +/*! + * \property QtIVIClimateZone::steeringWheelHeater + * \brief The steering wheel heater level. + * + * The steering wheel heater level, where the level can be \c 0 (off) or between \c 1 (least warm) + * to \c 10 (warmest). + */ +int QtIVIClimateZone::steeringWheelHeater() const +{ + return m_steeringWheelHeater; +} + +/*! + * \property QtIVIClimateZone::fanSpeedLevel + * \brief The fan speed level. + * + * The fan speed level, where the level can be \c 0 (off) or between \c 1 (weakest) to \c 10 + * (strongest). + */ +int QtIVIClimateZone::fanSpeedLevel() const +{ + return m_fanSpeedLevel; +} + +void QtIVIClimateControl::setAirflowDirection(QtIVIClimateControl::AirflowDirection ad) +{ + if(backend()) + backend()->setAirflowDirection(ad); +} + +void QtIVIClimateControl::setAirConditioningEnabled(bool e) +{ + if(backend()) + backend()->setAirConditioningEnabled(e); +} + +void QtIVIClimateControl::setHeaterEnabled(bool e) +{ + if(backend()) + backend()->setHeaterEnabled(e); +} + +void QtIVIClimateControl::setAirRecirculationEnabled(bool e) +{ + if(backend()) + backend()->setAirRecirculationEnabled(e); +} + +/*! + * Reimplemented from QtIVIAbstractFeature::acceptServiceObject() + */ +bool QtIVIClimateControl::acceptServiceObject(QtIVIServiceObject *so) +{ + return (qobject_cast<QtIVIClimateControlBackendInterface*>(so->interfaceInstance(QtIVIClimateControlBackendInterface::interfaceName)) != NULL); +} + +/*! + * Reimplemented from QtIVIAbstractFeature::connectToServiceObject() + */ +void QtIVIClimateControl::connectToServiceObject(QtIVIServiceObject *so) +{ + QtIVIClimateControlBackendInterface *backend = qobject_cast<QtIVIClimateControlBackendInterface*>(so->interfaceInstance(QtIVIClimateControlBackendInterface::interfaceName)); + + QStringList zones = backend->zones(); + foreach(const QString &z, zones) + m_zones[z] = new QtIVIClimateZone(z, this, backend); + + connect(backend, &QtIVIClimateControlBackendInterface::airflowDirectionChanged, this, &QtIVIClimateControl::onAirflowDirectionChanged); + connect(backend, &QtIVIClimateControlBackendInterface::airConditioningEnabledChanged, this, &QtIVIClimateControl::onAirConditioningEnabledChanged); + connect(backend, &QtIVIClimateControlBackendInterface::heaterEnabledChanged, this, &QtIVIClimateControl::onHeaterEnabledChanged); + connect(backend, &QtIVIClimateControlBackendInterface::airRecirculationEnabledChanged, this, &QtIVIClimateControl::onAirRecirculationEnabledChanged); + + onAirflowDirectionChanged(backend->airflowDirection()); + onAirConditioningEnabledChanged(backend->airConditioningEnabled()); + onHeaterEnabledChanged(backend->heaterEnabled()); + onAirRecirculationEnabledChanged(backend->airRecirculationEnabled()); + + zonesChanged(); +} + +/*! + * Reimplemented from QtIVIAbstractFeature::disconnectFromServiceObject() + */ +void QtIVIClimateControl::disconnectFromServiceObject(QtIVIServiceObject *so) +{ + QtIVIClimateControlBackendInterface *backend = qobject_cast<QtIVIClimateControlBackendInterface*>(so->interfaceInstance(QtIVIClimateControlBackendInterface::interfaceName)); + + while(m_zones.count() > 0) + delete m_zones.take(m_zones.firstKey()); + + zonesChanged(); + + disconnect(backend, &QtIVIClimateControlBackendInterface::airflowDirectionChanged, this, &QtIVIClimateControl::onAirflowDirectionChanged); + disconnect(backend, &QtIVIClimateControlBackendInterface::airConditioningEnabledChanged, this, &QtIVIClimateControl::onAirConditioningEnabledChanged); + disconnect(backend, &QtIVIClimateControlBackendInterface::heaterEnabledChanged, this, &QtIVIClimateControl::onHeaterEnabledChanged); + disconnect(backend, &QtIVIClimateControlBackendInterface::airRecirculationEnabledChanged, this, &QtIVIClimateControl::onAirRecirculationEnabledChanged); +} + +/*! + * Reimplemented from QtIVIAbstractFeature::clearServiceObject() + */ +void QtIVIClimateControl::clearServiceObject() +{ + /* Safe defaults */ + onAirflowDirectionChanged(QtIVIClimateControl::BiLevel); + onAirConditioningEnabledChanged(false); + onHeaterEnabledChanged(false); + onAirRecirculationEnabledChanged(false); + + while(m_zones.count() > 0) + delete m_zones.take(m_zones.firstKey()); + + zonesChanged(); +} + +void QtIVIClimateControl::onAirflowDirectionChanged(QtIVIClimateControl::AirflowDirection airflowDirection) +{ + m_airflowDirection = airflowDirection; + emit airflowDirectionChanged(m_airflowDirection); +} + +void QtIVIClimateControl::onAirConditioningEnabledChanged(bool airConditioning) +{ + m_airConditioning = airConditioning; + emit airConditioningEnabledChanged(m_airConditioning); +} + +void QtIVIClimateControl::onHeaterEnabledChanged(bool heater) +{ + m_heater = heater; + emit heaterEnabledChanged(m_heater); +} + +void QtIVIClimateControl::onAirRecirculationEnabledChanged(bool airRecirculation) +{ + m_airRecirculation = airRecirculation; + emit airRecirculationEnabledChanged(m_airRecirculation); +} + +QtIVIClimateControlBackendInterface *QtIVIClimateControl::backend() const +{ + if (serviceObject()) + return qobject_cast<QtIVIClimateControlBackendInterface*>(serviceObject()->interfaceInstance(QtIVIClimateControlBackendInterface::interfaceName)); + else + return 0; +} diff --git a/src/ivivehiclefunctions/qtiviclimatecontrol.h b/src/ivivehiclefunctions/qtiviclimatecontrol.h new file mode 100644 index 0000000..4bb4905 --- /dev/null +++ b/src/ivivehiclefunctions/qtiviclimatecontrol.h @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CLIMATECONTROL_H +#define CLIMATECONTROL_H + +#include <QtIVIVehicleFunctions/qtivivehiclefunctionsglobal.h> +#include <QtIVICore/QtIVIAbstractZoneModelFeature> +#include <QObject> +#include <QMap> + +class QtIVIClimateControl; +class QtIVIClimateControlBackendInterface; + +/* Properties based on http://www.w3.org/2014/automotive/data_spec.html#idl-def-ClimateControl + * This list contains properties per zone. + */ +class Q_QTIVIVEHICLEFUNCTIONS_EXPORT QtIVIClimateZone : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString zone READ zone CONSTANT) + + /* current setting of the desired temperature (Unit: celsius) */ + Q_PROPERTY(int targetTemperature READ targetTemperature WRITE setTargetTemperature NOTIFY targetTemperatureChanged) + /* current status of the seat ventilation ( 0: off, 1: least warm, 10: warmest ) */ + Q_PROPERTY(int seatCooler READ seatCooler WRITE setSeatCooler NOTIFY seatCoolerChanged) + /* current status of the seat warmer ( 0: off, 1: least warm, 10: warmest ) */ + Q_PROPERTY(int seatHeater READ seatHeater WRITE setSeatHeater NOTIFY seatHeaterChanged) + /* current status of steering wheel heater ( 0: off, 1: least warm, 10: warmest ) */ + Q_PROPERTY(int steeringWheelHeater READ steeringWheelHeater WRITE setSteeringWheelHeater NOTIFY steeringWheelHeaterChanged) + /* current status of the fan speed of the air flowing (0: off, 1: weakest, 10: strongest ) */ + Q_PROPERTY(int fanSpeedLevel READ fanSpeedLevel WRITE setFanSpeedLevel NOTIFY fanSpeedLevelChanged) + + Q_ENUMS(OptionalFeature) + +public: + enum OptionalFeature { + None = 0x0, + HasTargetTemperature = 0x1, + HasSeatCooler = 0x2, + HasSeatHeater = 0x4, + HasSteeringWheelHeater = 0x8, + HasFanSpeed = 0x10 + }; + Q_DECLARE_FLAGS(OptionalFeatures, OptionalFeature) + + bool hasFeature(OptionalFeature f) const; + + QString zone() const; + + int targetTemperature() const; + int seatCooler() const; + int seatHeater() const; + int steeringWheelHeater() const; + int fanSpeedLevel() const; + +public slots: + void setTargetTemperature(int); + void setSeatCooler(int); + void setSeatHeater(int); + void setSteeringWheelHeater(int); + void setFanSpeedLevel(int); + +signals: + void targetTemperatureChanged(int targetTemperature); + void seatCoolerChanged(int seatCooler); + void seatHeaterChanged(int seatHeater); + void steeringWheelHeaterChanged(int steeringWheelHeater); + void fanSpeedLevelChanged(int fanSpeedLevel); + +private slots: + void onTargetTemperatureChanged(const QString &z, int t); + void onSeatCoolerChanged(const QString &z, int t); + void onSeatHeaterChanged(const QString &z, int t); + void onSteeringWheelHeaterChanged(const QString &z, int steeringWheelHeater); + void onFanSpeedLevelChanged(const QString &z, int fanSpeedLevel); + +private: + friend class QtIVIClimateControl; + + QtIVIClimateZone(const QString &zone, QtIVIClimateControl *parent, QtIVIClimateControlBackendInterface *backend); + + QString m_zone; + + int m_targetTemperature; + int m_seatCooler; + int m_seatHeater; + int m_steeringWheelHeater; + int m_fanSpeedLevel; + + QFlags<OptionalFeature> m_features; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QtIVIClimateZone::OptionalFeatures) + + +/* Properties based on http://www.w3.org/2014/automotive/data_spec.html#idl-def-ClimateControl + * This list contains the properties for the whole car. + */ +class Q_QTIVIVEHICLEFUNCTIONS_EXPORT QtIVIClimateControl : public QtIVIAbstractZoneModelFeature +{ + Q_OBJECT + + /* airflow direction */ + Q_PROPERTY(AirflowDirection airflowDirection READ airflowDirection WRITE setAirflowDirection NOTIFY airflowDirectionChanged) + /* current status of the air conditioning system: on (true) or off (false) */ + Q_PROPERTY(bool airConditioning READ isAirConditioningEnabled WRITE setAirConditioningEnabled NOTIFY airConditioningEnabledChanged) + /* current status of the heating system: on (true) or off (false) */ + Q_PROPERTY(bool heater READ isHeaterEnabled WRITE setHeaterEnabled NOTIFY heaterEnabledChanged) + /* current setting of air recirculation: on (true) or pulling in outside air (false) */ + Q_PROPERTY(bool airRecirculation READ isAirRecirculationEnabled WRITE setAirRecirculationEnabled NOTIFY airRecirculationEnabledChanged) + + Q_ENUMS(AirflowDirection) + Q_ENUMS(OptionalFeature) + +public: + QtIVIClimateControl(QObject *parent=0); + + virtual QStringList zones() const; + virtual QObject *zoneObject(const QString &z) const; + QtIVIClimateZone *climateZoneObject(const QString &z) const; + + enum OptionalFeature { + None = 0x0, + HasAirflowDirection = 0x1, + HasAirConditioning = 0x2, + HasHeater = 0x4, + HasAirRecirculation = 0x8 + }; + Q_DECLARE_FLAGS(OptionalFeatures, OptionalFeature) + + bool hasFeature(OptionalFeature f) const; + + /* Based on http://www.w3.org/2014/automotive/data_spec.html#idl-def-AirflowDirection */ + enum AirflowDirection { + FloorPanel, + FloorDuct, + BiLevel, + DefrostFloor + }; + + AirflowDirection airflowDirection() const; + bool isAirConditioningEnabled() const; + bool isHeaterEnabled() const; + bool isAirRecirculationEnabled() const; + +public slots: + void setAirflowDirection(QtIVIClimateControl::AirflowDirection); + void setAirConditioningEnabled(bool); + void setHeaterEnabled(bool); + void setAirRecirculationEnabled(bool); + +signals: + void airflowDirectionChanged(QtIVIClimateControl::AirflowDirection airflowDirection); + void airConditioningEnabledChanged(bool airConditioning); + void heaterEnabledChanged(bool heaterEnabled); + void airRecirculationEnabledChanged(bool airRecirculation); + +protected: + virtual bool acceptServiceObject(QtIVIServiceObject *so); + virtual void connectToServiceObject(QtIVIServiceObject *so); + virtual void disconnectFromServiceObject(QtIVIServiceObject *so); + virtual void clearServiceObject(); + +private slots: + void onAirflowDirectionChanged(QtIVIClimateControl::AirflowDirection airflowDirection); + void onAirConditioningEnabledChanged(bool airConditioning); + void onHeaterEnabledChanged(bool heater); + void onAirRecirculationEnabledChanged(bool airRecirculation); + +private: + friend class QtIVIClimateZone; + + AirflowDirection m_airflowDirection; + bool m_airConditioning; + bool m_heater; + bool m_airRecirculation; + + QtIVIClimateControlBackendInterface *backend() const; + + QMap<QString, QtIVIClimateZone*> m_zones; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QtIVIClimateControl::OptionalFeatures) + +#endif // CLIMATECONTROL_H diff --git a/src/ivivehiclefunctions/qtiviclimatecontrolbackendinterface.h b/src/ivivehiclefunctions/qtiviclimatecontrolbackendinterface.h new file mode 100644 index 0000000..92fde2d --- /dev/null +++ b/src/ivivehiclefunctions/qtiviclimatecontrolbackendinterface.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIVICLIMATECONTROLBACKENDINTERFACE_H +#define QTIVICLIMATECONTROLBACKENDINTERFACE_H + +#include <QObject> + +#include "qtiviclimatecontrol.h" + +class Q_QTIVIVEHICLEFUNCTIONS_EXPORT QtIVIClimateControlBackendInterface : public QObject +{ + Q_OBJECT + +public: + QtIVIClimateControlBackendInterface(QObject *parent=0) : QObject(parent) {} + + static QString interfaceName; + + virtual QStringList zones() const = 0; + + virtual QtIVIClimateControl::OptionalFeatures climateFeatures() const = 0; + virtual QtIVIClimateZone::OptionalFeatures zoneFeatures(const QString &zone) const = 0; + + virtual void setTargetTemperature(const QString &zone, int) = 0; + virtual void setSeatCooler(const QString &zone, int) = 0; + virtual void setSeatHeater(const QString &zone, int) = 0; + virtual void setSteeringWheelHeater(const QString &zone, int) = 0; + virtual void setFanSpeedLevel(const QString &zone, int) = 0; + + virtual void setAirflowDirection(QtIVIClimateControl::AirflowDirection) = 0; + virtual void setAirConditioningEnabled(bool) = 0; + virtual void setHeaterEnabled(bool) = 0; + virtual void setAirRecirculationEnabled(bool) = 0; + + virtual int targetTemperature(const QString &zone) const = 0; + virtual int seatCooler(const QString &zone) const = 0; + virtual int seatHeater(const QString &zone) const = 0; + virtual int steeringWheelHeater(const QString &zone) const = 0; + virtual int fanSpeedLevel(const QString &zone) const = 0; + + virtual QtIVIClimateControl::AirflowDirection airflowDirection() const = 0; + virtual bool airConditioningEnabled() const = 0; + virtual bool heaterEnabled() const = 0; + virtual bool airRecirculationEnabled() const = 0; + +signals: + void targetTemperatureChanged(const QString &zone, int); + void seatCoolerChanged(const QString &zone, int); + void seatHeaterChanged(const QString &zone, int); + void steeringWheelHeaterChanged(const QString &zone, int); + void fanSpeedLevelChanged(const QString &zone, int); + + void airflowDirectionChanged(QtIVIClimateControl::AirflowDirection); + void airConditioningEnabledChanged(bool); + void heaterEnabledChanged(bool); + void airRecirculationEnabledChanged(bool); +}; + +#endif // QTIVICLIMATECONTROLBACKENDINTERFACE_H + diff --git a/src/ivivehiclefunctions/qtivivehiclefunctionsglobal.h b/src/ivivehiclefunctions/qtivivehiclefunctionsglobal.h new file mode 100644 index 0000000..c8f9380 --- /dev/null +++ b/src/ivivehiclefunctions/qtivivehiclefunctionsglobal.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTIVIVEHICLEFUNCTIONSGLOBAL_H +#define QTIVIVEHICLEFUNCTIONSGLOBAL_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_STATIC +# if defined(QT_BUILD_QTIVIVEHICLEFUNCTIONS_LIB) +# define Q_QTIVIVEHICLEFUNCTIONS_EXPORT Q_DECL_EXPORT +# else +# define Q_QTIVIVEHICLEFUNCTIONS_EXPORT Q_DECL_IMPORT +# endif +#else +# define Q_QTIVICORE_EXPORT +#endif + +QT_END_NAMESPACE + +#endif // QTIVIVEHICLEFUNCTIONSGLOBAL_H + diff --git a/src/plugins/ivivehiclefunctions/climate_simulator/climate_simulator.json b/src/plugins/ivivehiclefunctions/climate_simulator/climate_simulator.json new file mode 100644 index 0000000..048376a --- /dev/null +++ b/src/plugins/ivivehiclefunctions/climate_simulator/climate_simulator.json @@ -0,0 +1,3 @@ +{ + "interfaces" : [ "com.pelagicore.ClimateControl" ] +} diff --git a/src/plugins/ivivehiclefunctions/climate_simulator/climate_simulator.pro b/src/plugins/ivivehiclefunctions/climate_simulator/climate_simulator.pro new file mode 100644 index 0000000..14b4c6f --- /dev/null +++ b/src/plugins/ivivehiclefunctions/climate_simulator/climate_simulator.pro @@ -0,0 +1,18 @@ +TARGET = climate_simulator + +PLUGIN_TYPE = qtivi +PLUGIN_EXTENDS = qtivi +PLUGIN_CLASS_NAME = QtIVIClimateControlBackendInterface + +QT += core ivicore ivivehiclefunctions + +load(qt_plugin) + + +SOURCES += climateplugin.cpp \ + climatecontrolbackend.cpp + +HEADERS += climateplugin.h \ + climatecontrolbackend.h + +DISTFILES += climate_simulator.json diff --git a/src/plugins/ivivehiclefunctions/climate_simulator/climatecontrolbackend.cpp b/src/plugins/ivivehiclefunctions/climate_simulator/climatecontrolbackend.cpp new file mode 100644 index 0000000..93bcbf2 --- /dev/null +++ b/src/plugins/ivivehiclefunctions/climate_simulator/climatecontrolbackend.cpp @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "climatecontrolbackend.h" + +#include <QDebug> + +ClimateControlBackend::ClimateControlBackend(QObject *parent) : + QtIVIClimateControlBackendInterface(parent), + m_flowDirection(QtIVIClimateControl::BiLevel), + m_airCondition(true), + m_heater(true), + m_airRecirculation(false) +{ + ZoneBackend leftZone; + leftZone.features = QtIVIClimateZone::HasFanSpeed | + QtIVIClimateZone::HasSeatCooler | + QtIVIClimateZone::HasSeatHeater | + QtIVIClimateZone::HasSteeringWheelHeater | + QtIVIClimateZone::HasTargetTemperature; + leftZone.seatCooler = 10; + leftZone.seatHeater = 10; + leftZone.targetTemperature = 20; + leftZone.steeringWheelHeater = 0; + leftZone.fanSpeed = 10; + + m_zoneMap.insert("frontLeft",leftZone); + + ZoneBackend rightZone; + rightZone.features = QtIVIClimateZone::HasFanSpeed | + QtIVIClimateZone::HasSeatCooler | + QtIVIClimateZone::HasSeatHeater | + QtIVIClimateZone::HasTargetTemperature; + rightZone.seatCooler = 5; + rightZone.seatHeater = 0; + rightZone.targetTemperature = 10; + rightZone.steeringWheelHeater = 0; + rightZone.fanSpeed = 10; + + m_zoneMap.insert("frontRight",rightZone); + + ZoneBackend rearZone; + rearZone.features = QtIVIClimateZone::HasSeatHeater; + rearZone.seatCooler = 5; + rearZone.seatHeater = 0; + rearZone.targetTemperature = 10; + rearZone.steeringWheelHeater = 0; + rearZone.fanSpeed = 10; + + m_zoneMap.insert("rear",rearZone); +} + +ClimateControlBackend::~ClimateControlBackend() +{ +} + +QtIVIClimateControl::OptionalFeatures ClimateControlBackend::climateFeatures() const +{ + return QtIVIClimateControl::HasAirConditioning | + QtIVIClimateControl::HasAirflowDirection | + QtIVIClimateControl::HasAirRecirculation | + QtIVIClimateControl::HasHeater; +} + +QStringList ClimateControlBackend::zones() const +{ + return m_zoneMap.keys(); +} + +QtIVIClimateZone::OptionalFeatures ClimateControlBackend::zoneFeatures(const QString &zone) const +{ + if (!m_zoneMap.contains(zone)) + return QtIVIClimateZone::None; + + return m_zoneMap[zone].features; +} + +void ClimateControlBackend::setTargetTemperature(const QString &zone, int val) +{ + if (!m_zoneMap.contains(zone)) + return; + + if (m_zoneMap[zone].targetTemperature == val) + return; + + qWarning() << "SIMULATION TargetTemperature for Zone" << zone << "changed to" << val; + + m_zoneMap[zone].targetTemperature = val; + emit targetTemperatureChanged(zone, val); +} + +void ClimateControlBackend::setSeatCooler(const QString &zone, int val) +{ + if (!m_zoneMap.contains(zone)) + return; + + if (m_zoneMap[zone].seatCooler == val) + return; + + qWarning() << "SIMULATION SeatCooler for Zone" << zone << "changed to" << val; + + m_zoneMap[zone].seatCooler = val; + emit seatCoolerChanged(zone, val); +} + +void ClimateControlBackend::setSeatHeater(const QString &zone, int val) +{ + if (!m_zoneMap.contains(zone)) + return; + + if (m_zoneMap[zone].seatHeater == val) + return; + + qWarning() << "SIMULATION SeatHeater for Zone" << zone << "changed to" << val; + + m_zoneMap[zone].seatHeater = val; + emit seatHeaterChanged(zone, val); +} + +void ClimateControlBackend::setSteeringWheelHeater(const QString &zone, int val) +{ + if (!m_zoneMap.contains(zone)) + return; + + if (val < 0 || val > 10) { + qWarning() << "SIMULATION SteeringWheelHeater for Zone" << zone << "change out of range (0-10)" << val; + emit steeringWheelHeaterChanged(zone, m_zoneMap[zone].steeringWheelHeater); + return; + } + + if (m_zoneMap[zone].steeringWheelHeater == val) + return; + + qWarning() << "SIMULATION SteeringWheelHeater for" << zone << "changed to" << val; + + m_zoneMap[zone].steeringWheelHeater = val; + emit steeringWheelHeaterChanged(zone, val); +} + +void ClimateControlBackend::setFanSpeedLevel(const QString &zone, int speed) +{ + if (!m_zoneMap.contains(zone)) + return; + + if (speed < 0 || speed > 10) { + qWarning() << "SIMULATION FanSpeedLevel change out of range (0-10)" << speed; + emit fanSpeedLevelChanged(zone, m_zoneMap[zone].fanSpeed); + return; + } + + if (m_zoneMap[zone].fanSpeed == speed) + return; + + qWarning() << "SIMULATION FanSpeedLevel for Zone" << zone << "changed to" << speed; + + m_zoneMap[zone].fanSpeed = speed; + emit fanSpeedLevelChanged(zone, speed); +} + +void ClimateControlBackend::setAirflowDirection(QtIVIClimateControl::AirflowDirection direction) +{ + if (m_flowDirection == direction) + return; + + qWarning() << "SIMULATION AirflowDirection changed to" << direction; + + m_flowDirection = direction; + emit airflowDirectionChanged(direction); +} + +void ClimateControlBackend::setAirConditioningEnabled(bool val) +{ + if (m_airCondition == val) + return; + + qWarning() << "SIMULATION AirConditionEnabled changed to" << val; + + m_airCondition = val; + emit airConditioningEnabledChanged(val); +} + +void ClimateControlBackend::setHeaterEnabled(bool val) +{ + if (m_heater == val) + return; + + qWarning() << "SIMULATION HeaterEnabled changed to" << val; + + m_heater = val; + emit heaterEnabledChanged(val); +} + +void ClimateControlBackend::setAirRecirculationEnabled(bool val) +{ + if (m_heater == val) + return; + + qWarning() << "SIMULATION AirRecirculationEnabled changed to" << val; + + m_heater = val; + emit airRecirculationEnabledChanged(val); +} + +int ClimateControlBackend::targetTemperature(const QString &zone) const +{ + if (!m_zoneMap.contains(zone)) + return -1; + + return m_zoneMap[zone].targetTemperature; +} + +int ClimateControlBackend::seatCooler(const QString &zone) const +{ + if (!m_zoneMap.contains(zone)) + return -1; + + return m_zoneMap[zone].seatCooler; +} + +int ClimateControlBackend::seatHeater(const QString &zone) const +{ + if (!m_zoneMap.contains(zone)) + return -1; + + return m_zoneMap[zone].seatHeater; +} + +int ClimateControlBackend::steeringWheelHeater(const QString &zone) const +{ + if (!m_zoneMap.contains(zone)) + return -1; + + return m_zoneMap[zone].steeringWheelHeater; +} + +int ClimateControlBackend::fanSpeedLevel(const QString &zone) const +{ + if (!m_zoneMap.contains(zone)) + return -1; + + return m_zoneMap[zone].fanSpeed; +} + +QtIVIClimateControl::AirflowDirection ClimateControlBackend::airflowDirection() const +{ + return m_flowDirection; +} + +bool ClimateControlBackend::airConditioningEnabled() const +{ + return m_airCondition; +} + +bool ClimateControlBackend::heaterEnabled() const +{ + return m_heater; +} + +bool ClimateControlBackend::airRecirculationEnabled() const +{ + return m_airRecirculation; +} + diff --git a/src/plugins/ivivehiclefunctions/climate_simulator/climatecontrolbackend.h b/src/plugins/ivivehiclefunctions/climate_simulator/climatecontrolbackend.h new file mode 100644 index 0000000..ac4bc43 --- /dev/null +++ b/src/plugins/ivivehiclefunctions/climate_simulator/climatecontrolbackend.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CLIMATECONTROLBACKEND_H +#define CLIMATECONTROLBACKEND_H + +#include <QObject> +#include <QtIVIVehicleFunctions/QtIVIClimateControlBackendInterface> + +class ClimateControlBackend : public QtIVIClimateControlBackendInterface +{ +public: + ClimateControlBackend(QObject* parent = 0); + ~ClimateControlBackend(); + + // QtIVIClimateControlBackendInterface interface +public: + QStringList zones() const; + QtIVIClimateControl::OptionalFeatures climateFeatures() const; + QtIVIClimateZone::OptionalFeatures zoneFeatures(const QString &zone) const; + + int targetTemperature(const QString &zone) const; + int seatCooler(const QString &zone) const; + int seatHeater(const QString &zone) const; + int steeringWheelHeater(const QString &zone) const; + int fanSpeedLevel(const QString &zone) const; + + void setTargetTemperature(const QString &zone, int val); + void setSeatCooler(const QString &zone, int val); + void setSeatHeater(const QString &zone, int val); + void setSteeringWheelHeater(const QString &zone, int val); + void setFanSpeedLevel(const QString &zone, int); + + QtIVIClimateControl::AirflowDirection airflowDirection() const; + void setAirflowDirection(QtIVIClimateControl::AirflowDirection direction); + void setAirConditioningEnabled(bool val); + void setHeaterEnabled(bool val); + void setAirRecirculationEnabled(bool val); + bool airConditioningEnabled() const; + bool heaterEnabled() const; + bool airRecirculationEnabled() const; + +private: + + QtIVIClimateControl::AirflowDirection m_flowDirection; + bool m_airCondition; + bool m_heater; + bool m_airRecirculation; + + struct ZoneBackend { + QtIVIClimateZone::OptionalFeatures features; + + int targetTemperature; + int seatCooler; + int seatHeater; + int steeringWheelHeater; + int fanSpeed; + }; + + QMap<QString,ZoneBackend> m_zoneMap; +}; + +#endif // CLIMATECONTROLBACKEND_H diff --git a/src/plugins/ivivehiclefunctions/climate_simulator/climateplugin.cpp b/src/plugins/ivivehiclefunctions/climate_simulator/climateplugin.cpp new file mode 100644 index 0000000..1f26805 --- /dev/null +++ b/src/plugins/ivivehiclefunctions/climate_simulator/climateplugin.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "climateplugin.h" +#include "climatecontrolbackend.h" + +#include <QtIVIVehicleFunctions/QtIVIClimateControlBackendInterface> +#include <QStringList> + +ClimatePlugin::ClimatePlugin(QObject *parent) : + QObject(parent), + m_climate(new ClimateControlBackend(this)) +{ +} + +QStringList ClimatePlugin::interfaces() const +{ + QStringList list; + list << QtIVIClimateControlBackendInterface::interfaceName; + return list; +} + +QObject *ClimatePlugin::interfaceInstance(const QString &interface) const +{ + if (interface != QtIVIClimateControlBackendInterface::interfaceName) + return 0; + + return m_climate; +} diff --git a/src/plugins/ivivehiclefunctions/climate_simulator/climateplugin.h b/src/plugins/ivivehiclefunctions/climate_simulator/climateplugin.h new file mode 100644 index 0000000..74d8a07 --- /dev/null +++ b/src/plugins/ivivehiclefunctions/climate_simulator/climateplugin.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CLIMATEPLUGIN_H +#define CLIMATEPLUGIN_H + +#include <QtIVICore/QtIVIServiceInterface> + +class ClimateControlBackend; + +class ClimatePlugin : public QObject, QtIVIServiceInterface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.pelagicore.QtIVIServiceInterface" FILE "climate_simulator.json") + Q_INTERFACES(QtIVIServiceInterface) + +public: + ClimatePlugin(QObject *parent = 0); + + QStringList interfaces() const; + QObject* interfaceInstance(const QString& interface) const; + +private: + ClimateControlBackend* m_climate; +}; + +#endif // CLIMATEPLUGIN_H diff --git a/src/plugins/ivivehiclefunctions/ivivehiclefunctions.pro b/src/plugins/ivivehiclefunctions/ivivehiclefunctions.pro new file mode 100644 index 0000000..e1bf16c --- /dev/null +++ b/src/plugins/ivivehiclefunctions/ivivehiclefunctions.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = climate_simulator + diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro new file mode 100644 index 0000000..a1b4047 --- /dev/null +++ b/src/plugins/plugins.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = ivivehiclefunctions + diff --git a/src/src.pro b/src/src.pro index 58312e1..2c5b8d4 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,4 +1,9 @@ TEMPLATE = subdirs +SUBDIRS = ivicore \ + ivivehiclefunctions \ + plugins \ + imports + config_dlt { SUBDIRS += geniviextras } else { diff --git a/sync.profile b/sync.profile index 359adf3..56f08d4 100644 --- a/sync.profile +++ b/sync.profile @@ -1,9 +1,23 @@ -%modules = ( +%modules = ( # path to module name map + "QtIVICore" => "$basedir/src/ivicore", + "QtIVIVehicleFunctions" => "$basedir/src/ivivehiclefunctions", "QtGeniviExtras" => "$basedir/src/geniviextras", ); +%moduleheaders = ( # restrict the module headers to those found in relative path +); %classnames = ( "qdlt.h" => "QtDlt", ); +%deprecatedheaders = ( +); +$publicclassregexp = "Q.+"; +# Module dependencies. +# Every module that is required to build this module should have one entry. +# Each of the module version specifiers can take one of the following values: +# - A specific Git revision. +# - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch) +# %dependencies = ( "qtbase" => "refs/heads/stable", ); + diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 2fc5f59..19d6d69 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,5 +1,7 @@ TEMPLATE = subdirs + +SUBDIRS = core vehiclefunctions +TEMPLATE = subdirs qtHaveModule(geniviextras) { SUBDIRS += dlt } - diff --git a/tests/auto/core/core.pro b/tests/auto/core/core.pro new file mode 100644 index 0000000..6a98ecd --- /dev/null +++ b/tests/auto/core/core.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +SUBDIRS = servicemanagertest diff --git a/tests/auto/core/servicemanagertest/servicemanagertest.pro b/tests/auto/core/servicemanagertest/servicemanagertest.pro new file mode 100644 index 0000000..dc5a5c7 --- /dev/null +++ b/tests/auto/core/servicemanagertest/servicemanagertest.pro @@ -0,0 +1,11 @@ +QT += testlib ivicore + +TARGET = tst_servicemanagertest +CONFIG += testcase + +TEMPLATE = app + +SOURCES += \ + tst_servicemanagertest.cpp + +DEFINES += SRCDIR=\\\"$$PWD/\\\" diff --git a/tests/auto/core/servicemanagertest/tst_servicemanagertest.cpp b/tests/auto/core/servicemanagertest/tst_servicemanagertest.cpp new file mode 100644 index 0000000..f12695d --- /dev/null +++ b/tests/auto/core/servicemanagertest/tst_servicemanagertest.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QString> +#include <QtTest> +#include <qtiviservicemanager.h> +#include <qtiviserviceinterface.h> +#include <qtiviserviceobject.h> + +class MockServiceBackend : public QObject, public QtIVIServiceInterface +{ + Q_OBJECT + Q_INTERFACES(QtIVIServiceInterface) + +public: + MockServiceBackend(QObject *parent=0) : QObject(parent) + { + } + + QStringList interfaces() const { + return m_serviceObjects.keys(); + } + + QObject* interfaceInstance(const QString &interface) const { + return m_serviceObjects.value(interface); + } + + void addServiceObject(const QString &interface, QObject *serviceObject) { + if (!serviceObject->parent()) + serviceObject->setParent(this); + + m_serviceObjects.insert(interface, serviceObject); + } + +private: + QMap<QString, QObject *> m_serviceObjects; +}; + +class ServiceManagerTest : public QObject +{ + Q_OBJECT + +public: + ServiceManagerTest(); + +private Q_SLOTS: + void cleanup(); + + void testHasInterface(); + void testFindServiceObjectsReturnInValidInstance(); + void testFindServiceObjects(); + void testRegisterWithNoInterfaces(); + void testRegisterNonServiceBackendInterfaceObject(); + void testManagerListModel(); + +private: + QtIVIServiceManager *manager; +}; + +ServiceManagerTest::ServiceManagerTest() +{ + manager = QtIVIServiceManager::instance(); +} + +void ServiceManagerTest::cleanup() +{ + manager->unloadAllBackends(); +} + +#define COMPARE_SERVICE_OBJECT(_model_, _index_, _serviceObject_) \ +do { \ + QString name = _model_->data(_model_->index(_index_), Qt::DisplayRole).toString(); \ + QCOMPARE(name, _serviceObject_->name()); \ +\ + QStringList list = _model_->data(_model_->index(_index_), ServiceObjectModel::InterfacesRole).toStringList(); \ + QCOMPARE(list, _serviceObject_->interfaces()); \ +\ + ServiceObject *so = _model_->data(_model_->index(_index_), ServiceObjectModel::ServiceObjectRole).value<ServiceObject*>(); \ + QCOMPARE(so, _serviceObject_); \ +} while (0) + +/* + * Test the hasInterface method + */ +void ServiceManagerTest::testHasInterface() +{ + QCOMPARE(manager->hasInterface("Foo"), false); + + MockServiceBackend *backend0 = new MockServiceBackend(manager); + bool regResult = manager->registerService(backend0, QStringList() << "Foo" << "Bar"); + QCOMPARE(regResult, true); + QCOMPARE(manager->hasInterface("Foo"), true); + QCOMPARE(manager->hasInterface("Bar"), true); +} + +void ServiceManagerTest::testFindServiceObjectsReturnInValidInstance() +{ + QList<QtIVIServiceObject*> list = manager->findServiceByInterface("NonExistingInterface"); + QVERIFY(list.isEmpty()); +} + +void ServiceManagerTest::testFindServiceObjects() +{ + MockServiceBackend *backend = new MockServiceBackend(manager); + bool regResult = manager->registerService(backend, QStringList() << "TestInterface"); + QCOMPARE(regResult, true); + QObject* testObject = new QObject(); + backend->addServiceObject("TestInterface", testObject); + + QList<QtIVIServiceObject*> list = manager->findServiceByInterface("TestInterface"); + QVERIFY(!list.isEmpty()); + QtIVIServiceObject* serviceObject = list.at(0); + QVERIFY(serviceObject->interfaces().contains("TestInterface")); + QCOMPARE(serviceObject->interfaceInstance("TestInterface"), testObject); +} + +/* + * Test that the registerService method returns false if the user tries + * to register a service with an empty list of interfaces. + */ +void ServiceManagerTest::testRegisterWithNoInterfaces() +{ + MockServiceBackend *backend = new MockServiceBackend(manager); + bool regResult = manager->registerService(backend, QStringList()); + QCOMPARE(regResult, false); +} + +/* + * Test that the registerService method returns false if the user tries + * to register a service which doesn't implement the ServiceBackendInterface. + */ +void ServiceManagerTest::testRegisterNonServiceBackendInterfaceObject() +{ + QObject *anyObject = new QObject(manager); + bool regResult = manager->registerService(anyObject, QStringList() << "Interface"); + QCOMPARE(regResult, false); + QCOMPARE(manager->hasInterface("Interface"), false); +} + +/* + * Test typical QAbstractListModel behavior + */ +void ServiceManagerTest::testManagerListModel() +{ + QSignalSpy managerModelSpy(manager, SIGNAL(rowsInserted(QModelIndex,int,int))); + + // Sanity check + QCOMPARE(manager->rowCount(), 0); + QCOMPARE(managerModelSpy.count(), 0); + + // Register backend-0 with 'Interface0' + MockServiceBackend *backend0 = new MockServiceBackend(manager); + bool regResult = manager->registerService(backend0, QStringList() << "Interface0"); + QCOMPARE(regResult, true); + QCOMPARE(manager->rowCount(), 1); + //QCOMPARE(manager->data(manager->index(0), Qt::DisplayRole).value<QtIVIServiceInterface*>, QString("Interface0")); + QCOMPARE(managerModelSpy.count(), 1); + + // Register backend-1 with 'Interface1' and 'Interface2'. Should change the model + MockServiceBackend *backend1 = new MockServiceBackend(manager); + regResult = manager->registerService(backend1, QStringList() << "Interface1" << "Interface2"); + QCOMPARE(regResult, true); + QCOMPARE(manager->rowCount(), 2); + //QCOMPARE(manager->data(manager->index(1), ServiceManager::InterfaceRole).toString(), QString("Interface1")); + //QCOMPARE(manager->data(manager->index(2), Qt::DisplayRole).toString(), QString("Interface2")); + QCOMPARE(managerModelSpy.count(), 2); + + // Register backend-2 with 'Interface1' and 'Interface2'. Should not result in any model changes + MockServiceBackend *backend2 = new MockServiceBackend(manager); + regResult = manager->registerService(backend2, QStringList() << "Interface1" << "Interface2"); + QCOMPARE(regResult, true); + QCOMPARE(manager->rowCount(), 3); + QCOMPARE(managerModelSpy.count(), 3); +} + +QTEST_APPLESS_MAIN(ServiceManagerTest) + +#include "tst_servicemanagertest.moc" diff --git a/tests/auto/vehiclefunctions/climatecontroltest/climatecontroltest.pro b/tests/auto/vehiclefunctions/climatecontroltest/climatecontroltest.pro new file mode 100644 index 0000000..cd965da --- /dev/null +++ b/tests/auto/vehiclefunctions/climatecontroltest/climatecontroltest.pro @@ -0,0 +1,11 @@ +QT += testlib ivicore ivivehiclefunctions + +TARGET = tst_climatecontroltest +CONFIG += testcase + +TEMPLATE = app + +SOURCES += \ + tst_climatecontroltest.cpp + +DEFINES += SRCDIR=\\\"$$PWD/\\\" diff --git a/tests/auto/vehiclefunctions/climatecontroltest/tst_climatecontroltest.cpp b/tests/auto/vehiclefunctions/climatecontroltest/tst_climatecontroltest.cpp new file mode 100644 index 0000000..a8bae72 --- /dev/null +++ b/tests/auto/vehiclefunctions/climatecontroltest/tst_climatecontroltest.cpp @@ -0,0 +1,485 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.pelagicore.com/ +** +** This file is part of Qt IVI. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt IVI licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Pelagicore. For licensing terms +** and conditions see http://www.pelagicore.com. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest> +#include "qtiviservicemanager.h" +#include "qtiviserviceobject.h" +#include "qtiviclimatecontrol.h" +#include "qtiviclimatecontrolbackendinterface.h" + +class ClimateControlTestBackend : public QtIVIClimateControlBackendInterface +{ +public: + ClimateControlTestBackend() + : QtIVIClimateControlBackendInterface() + , m_airflowDirection(QtIVIClimateControl::DefrostFloor) + , m_airConditioningEnabled(false) + , m_heaterEnabled(false) + , m_airRecirculationEnabled(false) + { + QStringList zones; + zones << "frontLeft" << "Upper" << "Lower"; + foreach (const QString &z, zones) { + m_zoneFeatures[z] = QtIVIClimateZone::HasFanSpeed | QtIVIClimateZone::HasSeatCooler | QtIVIClimateZone::HasSeatHeater | QtIVIClimateZone::HasSteeringWheelHeater | QtIVIClimateZone::HasTargetTemperature; + m_zoneTargetTemperature[z] = 0; + m_zoneSeatCooler[z] = 0; + m_zoneSeatHeater[z] = 0; + m_zoneSteeringWheelHeater[z] = 0; + m_zoneFanSpeedLevel[z] = 0; + } + } + + QStringList zones() const + { + return m_zoneTargetTemperature.keys(); + } + + QtIVIClimateControl::OptionalFeatures climateFeatures() const + { + return QtIVIClimateControl::HasAirConditioning | + QtIVIClimateControl::HasAirflowDirection | + QtIVIClimateControl::HasAirRecirculation | + QtIVIClimateControl::HasHeater; + } + + QtIVIClimateZone::OptionalFeatures zoneFeatures(const QString &z) const + { + if (!m_zoneFeatures.contains(z)) + return QtIVIClimateZone::None; + + return m_zoneFeatures[z]; + } + + void setTargetTemperature(const QString &z, int t) + { + if (!m_zoneTargetTemperature.contains(z)) + return; + + if (!m_zoneFeatures[z].testFlag(QtIVIClimateZone::HasTargetTemperature)) + return; + + if (m_zoneTargetTemperature[z] != t){ + m_zoneTargetTemperature[z] = t; + emit targetTemperatureChanged(z, m_zoneTargetTemperature[z]); + } + } + + void setSeatCooler(const QString &z, int t) + { + if (!m_zoneSeatCooler.contains(z)) + return; + + if (!m_zoneFeatures[z].testFlag(QtIVIClimateZone::HasSeatCooler)) + return; + + if (m_zoneSeatCooler[z] != t) { + m_zoneSeatCooler[z] = t; + emit seatCoolerChanged(z, m_zoneSeatCooler[z]); + } + } + + void setSeatHeater(const QString &z, int t) + { + if (!m_zoneSeatHeater.contains(z)) + return; + + if (!m_zoneFeatures[z].testFlag(QtIVIClimateZone::HasSeatHeater)) + return; + + if (m_zoneSeatHeater[z] != t) { + m_zoneSeatHeater[z] = t; + emit seatHeaterChanged(z, m_zoneSeatHeater[z]); + } + } + + void setAirflowDirection(QtIVIClimateControl::AirflowDirection ad) + { + if (!climateFeatures().testFlag(QtIVIClimateControl::HasAirflowDirection)) + return; + + if (m_airflowDirection != ad) { + m_airflowDirection = ad; + emit airflowDirectionChanged(m_airflowDirection); + } + } + + void setAirConditioningEnabled(bool e) + { + if (!climateFeatures().testFlag(QtIVIClimateControl::HasAirConditioning)) + return; + + if (m_airConditioningEnabled != e) { + m_airConditioningEnabled = e; + emit airConditioningEnabledChanged(m_airConditioningEnabled); + } + } + + void setHeaterEnabled(bool e) + { + if (!climateFeatures().testFlag(QtIVIClimateControl::HasHeater)) + return; + + if (m_heaterEnabled != e) { + m_heaterEnabled = e; + emit heaterEnabledChanged(m_heaterEnabled); + } + } + + void setAirRecirculationEnabled(bool e) + { + if (!climateFeatures().testFlag(QtIVIClimateControl::HasAirRecirculation)) + return; + + if (m_airRecirculationEnabled != e) { + m_airRecirculationEnabled = e; + emit airRecirculationEnabledChanged(m_airRecirculationEnabled); + } + } + + void setSteeringWheelHeater(const QString &z, int t) + { + if (!m_zoneSteeringWheelHeater.contains(z)) + return; + + if (!m_zoneFeatures[z].testFlag(QtIVIClimateZone::HasSteeringWheelHeater)) + return; + + if (m_zoneSteeringWheelHeater[z] != t) { + m_zoneSteeringWheelHeater[z] = t; + emit steeringWheelHeaterChanged(z, m_zoneSteeringWheelHeater[z]); + } + } + + void setFanSpeedLevel(const QString &z, int fsl) + { + if (!m_zoneFanSpeedLevel.contains(z)) + return; + + if (!m_zoneFeatures[z].testFlag(QtIVIClimateZone::HasFanSpeed)) + return; + + if (fsl < 0 || fsl > 10) { + qWarning() << "Attempted to set Zone" << z << "fanSpeedLevel to" << fsl << " which is out of range (0-10)."; + return; + } + + if (m_zoneFanSpeedLevel[z] != fsl) { + m_zoneFanSpeedLevel[z] = fsl; + emit fanSpeedLevelChanged(z, m_zoneFanSpeedLevel[z]); + } + } + + int targetTemperature(const QString &z) const + { + return m_zoneTargetTemperature[z]; + } + + int seatCooler(const QString &z) const + { + return m_zoneSeatCooler[z]; + } + + int seatHeater(const QString &z) const + { + return m_zoneSeatHeater[z]; + } + + QtIVIClimateControl::AirflowDirection airflowDirection() const + { + return m_airflowDirection; + } + + bool airConditioningEnabled() const + { + return m_airConditioningEnabled; + } + + bool heaterEnabled() const + { + return m_heaterEnabled; + } + + bool airRecirculationEnabled() const + { + return m_airRecirculationEnabled; + } + + int steeringWheelHeater(const QString &z) const + { + return m_zoneSteeringWheelHeater[z]; + } + + int fanSpeedLevel(const QString &z) const + { + return m_zoneFanSpeedLevel[z]; + } + + void setHasFeature(const QString &z, QtIVIClimateZone::OptionalFeature f, bool e) + { + if (e) + m_zoneFeatures[z] |= f; + else + m_zoneFeatures[z] &= ~f; + } + +private: + QtIVIClimateControl::AirflowDirection m_airflowDirection; + bool m_airConditioningEnabled; + bool m_heaterEnabled; + bool m_airRecirculationEnabled; + + QMap<QString, QtIVIClimateZone::OptionalFeatures> m_zoneFeatures; + QMap<QString, int> m_zoneTargetTemperature; + QMap<QString, int> m_zoneSeatCooler; + QMap<QString, int> m_zoneSeatHeater; + QMap<QString, int> m_zoneSteeringWheelHeater; + QMap<QString, int> m_zoneFanSpeedLevel; +}; + +class ClimateControlTestServiceObject : public QtIVIServiceObject { + +public: + explicit ClimateControlTestServiceObject(QObject *parent=0) : + QtIVIServiceObject(parent), m_name(QLatin1String("")) + { + m_interfaces << QtIVIClimateControlBackendInterface::interfaceName; + } + + QString name() const { return m_name; } + QStringList interfaces() const { return m_interfaces; } + QObject* interfaceInstance(const QString& interface) const + { + if (interface == QtIVIClimateControlBackendInterface::interfaceName) + return testBackend(); + else + return 0; + } + + ClimateControlTestBackend *testBackend() const + { + static ClimateControlTestBackend backend; + return &backend; + } + +private: + QString m_name; + QStringList m_interfaces; +}; + +class ClimateControlTest : public QObject +{ + Q_OBJECT + +public: + ClimateControlTest(); + +private slots: + void cleanup(); + + void testWithoutBackend(); +// TODO void testAirConditioningEnabled(); + void testHeaterEnabled(); + void testAirRecirculationEnabled(); + + void testZoneFanSpeedLevel(); + void testZoneSteeringWheelHeater(); + + void testZoneTargetTemperature(); + void testZoneSeatCooler(); + void testZoneSeatHeater(); + + void testZoneWithoutTargetTemperature(); + void testZoneWithoutSeatCooler(); + void testZoneWithoutSeatHeater(); + +private: + QtIVIServiceManager *manager; +}; + +ClimateControlTest::ClimateControlTest() + : QObject() +{ + manager = QtIVIServiceManager::instance(); +} + +void ClimateControlTest::cleanup() +{ + manager->unloadAllBackends(); +} + +void ClimateControlTest::testWithoutBackend() +{ + QtIVIClimateControl cc; + + // Running without a backend means that changes do not propagate + // We check this on a single property in this case + QSignalSpy heaterEnabledSpy(&cc, SIGNAL(heaterEnabledChanged(bool))); + + bool e = cc.isHeaterEnabled(); + QCOMPARE(e, false); + cc.setHeaterEnabled(true); + QCOMPARE(heaterEnabledSpy.count(), 0); + QCOMPARE(cc.isHeaterEnabled(), e); + + QCOMPARE(cc.zones().count(), 0); +} + +/* For testing integer properties of the climate control */ +#define TEST_INTEGER_PROPERTY(_prop_, _capitalProp_) \ +void ClimateControlTest::test##_capitalProp_() { \ + ClimateControlTestServiceObject *service = new ClimateControlTestServiceObject(); \ + manager->registerService(service, service->interfaces()); \ + service->testBackend()->set##_capitalProp_(0); \ + QtIVIClimateControl cc; \ + cc.startAutoDiscovery(); \ + QSignalSpy valueSpy(&cc, SIGNAL(_prop_##Changed(int))); \ + QCOMPARE(cc._prop_(), 0); \ + QCOMPARE(cc.property(#_prop_).toInt(), 0); \ + cc.set##_capitalProp_(5); \ + QCOMPARE(valueSpy.count(), 1); \ + QCOMPARE(valueSpy.takeFirst().at(0).toInt(), 5); \ + QCOMPARE(cc._prop_(), 5); \ + QCOMPARE(cc.property(#_prop_).toInt(), 5); \ + service->testBackend()->set##_capitalProp_(8); \ + QCOMPARE(valueSpy.count(), 1); \ + QCOMPARE(valueSpy.takeFirst().at(0).toInt(), 8); \ + QCOMPARE(cc._prop_(), 8); \ + QCOMPARE(cc.property(#_prop_).toInt(), 8); \ + cc.setProperty(#_prop_, 6); \ + QCOMPARE(valueSpy.count(), 1); \ + QCOMPARE(valueSpy.takeFirst().at(0).toInt(), 6); \ + QCOMPARE(cc._prop_(), 6); \ + QCOMPARE(cc.property(#_prop_).toInt(), 6); \ +} + +/* For testing boolean properties of the climate control */ +#define TEST_BOOLEAN_PROPERTY(_prop_, _capitalProp_) \ +void ClimateControlTest::test##_capitalProp_##Enabled() { \ + ClimateControlTestServiceObject *service = new ClimateControlTestServiceObject(); \ + manager->registerService(service, service->interfaces()); \ + service->testBackend()->set##_capitalProp_##Enabled(false); \ + QtIVIClimateControl cc; \ + cc.startAutoDiscovery(); \ + QSignalSpy valueSpy(&cc, SIGNAL(_prop_##EnabledChanged(bool))); \ + QCOMPARE(cc.is##_capitalProp_##Enabled(), false); \ + QCOMPARE(cc.property(#_prop_).toBool(), false); \ + cc.set##_capitalProp_##Enabled(true); \ + QCOMPARE(valueSpy.count(), 1); \ + QCOMPARE(valueSpy.takeFirst().at(0).toBool(), true); \ + QCOMPARE(cc.is##_capitalProp_##Enabled(), true); \ + QCOMPARE(cc.property(#_prop_).toBool(), true); \ + service->testBackend()->set##_capitalProp_##Enabled(false); \ + QCOMPARE(valueSpy.count(), 1); \ + QCOMPARE(valueSpy.takeFirst().at(0).toBool(), false); \ + QCOMPARE(cc.is##_capitalProp_##Enabled(), false); \ + QCOMPARE(cc.property(#_prop_).toBool(), false); \ + cc.setProperty(#_prop_, true); \ + QCOMPARE(valueSpy.count(), 1); \ + QCOMPARE(valueSpy.takeFirst().at(0).toBool(), true); \ + QCOMPARE(cc.is##_capitalProp_##Enabled(), true); \ + QCOMPARE(cc.property(#_prop_).toBool(), true); \ +} + +/* For testing integer properties of the climate zones */ +#define TEST_INTEGER_ZONE_PROPERTY(_prop_, _capitalProp_) \ +void ClimateControlTest::testZone##_capitalProp_() { \ + ClimateControlTestServiceObject *service = new ClimateControlTestServiceObject(); \ + manager->registerService(service, service->interfaces()); \ + QtIVIClimateControl cc; \ + cc.startAutoDiscovery(); \ + QStringList zones = cc.zones(); \ + foreach(const QString &z, zones) { \ + service->testBackend()->set##_capitalProp_(z, 0); \ + QSignalSpy valueSpy(cc.climateZoneObject(z), SIGNAL(_prop_##Changed(int))); \ + QCOMPARE(cc.climateZoneObject(z)->_prop_(), 0); \ + QCOMPARE(cc.climateZoneObject(z)->property(#_prop_).toInt(), 0); \ + cc.climateZoneObject(z)->set##_capitalProp_(5); \ + QCOMPARE(valueSpy.count(), 1); \ + QCOMPARE(valueSpy.takeFirst().at(0).toInt(), 5); \ + QCOMPARE(cc.climateZoneObject(z)->_prop_(), 5); \ + QCOMPARE(cc.climateZoneObject(z)->property(#_prop_).toInt(), 5); \ + service->testBackend()->set##_capitalProp_(z, 8); \ + QCOMPARE(valueSpy.count(), 1); \ + QCOMPARE(valueSpy.takeFirst().at(0).toInt(), 8); \ + QCOMPARE(cc.climateZoneObject(z)->_prop_(), 8); \ + QCOMPARE(cc.climateZoneObject(z)->property(#_prop_).toInt(), 8); \ + cc.climateZoneObject(z)->setProperty(#_prop_, 6); \ + QCOMPARE(valueSpy.count(), 1); \ + QCOMPARE(valueSpy.takeFirst().at(0).toInt(), 6); \ + QCOMPARE(cc.climateZoneObject(z)->_prop_(), 6); \ + QCOMPARE(cc.climateZoneObject(z)->property(#_prop_).toInt(), 6); \ + } \ +} + +/* For testing unavailable integer properties of the climate zones */ +#define TEST_WITHOUT_INTEGER_ZONE_PROPERTY(_prop_, _capitalProp_) \ +void ClimateControlTest::testZoneWithout##_capitalProp_() { \ + ClimateControlTestServiceObject *service = new ClimateControlTestServiceObject(); \ + manager->registerService(service, service->interfaces()); \ + QStringList zones; zones << "frontLeft" << "Upper" << "Lower"; \ + foreach(const QString &z, zones) \ + service->testBackend()->setHasFeature(z, QtIVIClimateZone::Has##_capitalProp_, false); \ + QtIVIClimateControl cc; \ + cc.startAutoDiscovery(); \ + zones = cc.zones(); \ + foreach(const QString &z, zones) { \ + service->testBackend()->set##_capitalProp_(z, 0); \ + QSignalSpy valueSpy(cc.climateZoneObject(z), SIGNAL(_prop_##Changed(int))); \ + QCOMPARE(cc.climateZoneObject(z)->_prop_(), 0); \ + QCOMPARE(cc.climateZoneObject(z)->property(#_prop_).toInt(), 0); \ + QTest::ignoreMessage(QtWarningMsg, "Trying to set ClimateZone::" #_prop_ " in an unsupported zone or without a backend."); \ + cc.climateZoneObject(z)->set##_capitalProp_(5); \ + QCOMPARE(valueSpy.count(), 0); \ + QCOMPARE(cc.climateZoneObject(z)->_prop_(), 0); \ + QCOMPARE(cc.climateZoneObject(z)->property(#_prop_).toInt(), 0); \ + service->testBackend()->set##_capitalProp_(z, 8); \ + QCOMPARE(valueSpy.count(), 0); \ + QCOMPARE(cc.climateZoneObject(z)->_prop_(), 0); \ + QCOMPARE(cc.climateZoneObject(z)->property(#_prop_).toInt(), 0); \ + QTest::ignoreMessage(QtWarningMsg, "Trying to set ClimateZone::" #_prop_ " in an unsupported zone or without a backend."); \ + cc.climateZoneObject(z)->setProperty(#_prop_, 6); \ + QCOMPARE(valueSpy.count(), 0); \ + QCOMPARE(cc.climateZoneObject(z)->_prop_(), 0); \ + QCOMPARE(cc.climateZoneObject(z)->property(#_prop_).toInt(), 0); \ + } \ +} + +// TODO TEST_BOOLEAN_PROPERTY(airConditioning, AirConditioning) +TEST_BOOLEAN_PROPERTY(heater, Heater) +TEST_BOOLEAN_PROPERTY(airRecirculation, AirRecirculation) +TEST_INTEGER_ZONE_PROPERTY(fanSpeedLevel, FanSpeedLevel) +TEST_INTEGER_ZONE_PROPERTY(steeringWheelHeater, SteeringWheelHeater) +TEST_INTEGER_ZONE_PROPERTY(targetTemperature, TargetTemperature) +TEST_INTEGER_ZONE_PROPERTY(seatCooler, SeatCooler) +TEST_INTEGER_ZONE_PROPERTY(seatHeater, SeatHeater) +TEST_WITHOUT_INTEGER_ZONE_PROPERTY(targetTemperature, TargetTemperature) +TEST_WITHOUT_INTEGER_ZONE_PROPERTY(seatCooler, SeatCooler) +TEST_WITHOUT_INTEGER_ZONE_PROPERTY(seatHeater, SeatHeater) + +QTEST_APPLESS_MAIN(ClimateControlTest) + +#include "tst_climatecontroltest.moc" diff --git a/tests/auto/vehiclefunctions/vehiclefunctions.pro b/tests/auto/vehiclefunctions/vehiclefunctions.pro new file mode 100644 index 0000000..682299a --- /dev/null +++ b/tests/auto/vehiclefunctions/vehiclefunctions.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +SUBDIRS = climatecontroltest diff --git a/tests/tests.pro b/tests/tests.pro index 157ef34..2ede516 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -1,2 +1,3 @@ TEMPLATE = subdirs -SUBDIRS += auto + +SUBDIRS = auto |