diff options
author | Dominik Holland <dominik.holland@pelagicore.com> | 2015-10-20 05:09:25 +0200 |
---|---|---|
committer | Alessandro Portale <alessandro.portale@theqtcompany.com> | 2015-12-03 16:26:52 +0000 |
commit | 716bdcc7a9c5c83bdeaf55b33ddd6acefce1a56b (patch) | |
tree | 893e681c4b1d478aaf2e54738b9ed213805fffb1 | |
parent | 4fa1d4f76d44afdf40707fb86f0aeeed1fb1c2ba (diff) |
Import source code from https://github.com/Pelagicore/qmllive
Change-Id: I6888c1c39c5e98c61511f74659b45ddcbb368956
Reviewed-by: Juergen Bocklage-Ryannel <juergen.bocklage-ryannel@pelagicore.com>
Reviewed-by: Alessandro Portale <alessandro.portale@theqtcompany.com>
179 files changed, 16896 insertions, 0 deletions
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/README.md b/README.md new file mode 100644 index 0000000..5afbfaa --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# QmlLive + +A live coding environment for QML. + +Allows to reload your qml scene when a file in your workspace changes. This can be done on the same host using the QmlLiveBench or on a remote device using the QmlLiveRuntime using the QmlLiveBench as server. + +## Sub Projects + +- qmllivebench - the qml-live workbench. All inclusive +- qmllivert - a default qml-live runtime for easy use +- src - common source code shared by all projects + +## Desktop + +For desktop usage just compile livebench. + + $ qmake + $ make + $ ./bin/qmllivebench + +The project files will automatically detect the qt version and enables +or disables some features based on that. + + +## Using QmlLiveBench + +Open QmlLiveBench on your host system and use File->Open Workspace to open your workspace. QmlLiveBench will observe all file changes in the directory and all sub-directories. Now you need to select a QML file in the workspace file viewer to start the rendering. + +When you now edit and save a file. The the changes wil be applied and the rendering reloaded. This goes in a fraction of a second. + +If you scene needs additional imports you can specify them under the settings dialog. Here you will also find the proxy information and the configurations for the target devices. + +## Running a remote session + +Configuring the target: + +Make sure you have any required imports available, which are either not in the workspace or are native pulgins. The qml files will be +provided by the remote client using a synchronization protocol. Create a clean directory and start qmlliveruntime from there, passing any required imports using -importpath. + +Connecting with the client: + +Start qmlliveremote on your host machine. Open the qml workspace and connect to +the target. Enable Publish changes and press Publish all to transfer the entire +workspace to the target. Click on the qml file you want to run, it should start +on the target. Edit using your favorite tools on the host and instantly get the +changes on the target when saving. + +# Contributions + +* Dominik Holland - Thank you for shouldering most of the work and to ensure the IPC code is rock-solid. +* Robert Griebl - Thank you for knowing so many details on Qt and helping with the internals. +* Juergen Bocklage-Ryannel - For providing the initial idea and believing into the product. + +Copyright (C) 2015 Pelagicore diff --git a/base.pri b/base.pri new file mode 100644 index 0000000..0bb418b --- /dev/null +++ b/base.pri @@ -0,0 +1,3 @@ +#TEMP_DIR = _build +#OBJECTS_DIR = $$TEMP_DIR/obj +#MOC_DIR = $$TEMP_DIR/moc diff --git a/doc/Doxyfile b/doc/Doxyfile new file mode 100644 index 0000000..1ca50ed --- /dev/null +++ b/doc/Doxyfile @@ -0,0 +1,1846 @@ +# Doxyfile 1.8.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = QmlLive + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = /Users/jryannel/repos/qml-live/doc/ + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behavior. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behavior instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = /Users/jryannel/repos/qml-live/src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = ../src + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# manageable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/doc/classes.qdoc b/doc/classes.qdoc new file mode 100644 index 0000000..86844e4 --- /dev/null +++ b/doc/classes.qdoc @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +/*! + \group classlists + \title Class and Function Documentation + \brief Lists and Indexes of classes, functions, and types. + + Links to indexes and lists for finding class and function + reference documentation. + + \section2 Class Lists + + \annotatedlist classlists + + \section2 Function Lists + + \annotatedlist funclists + +*/ + +/*! + \page classes.html + \title All Classes + \ingroup classlists + + \brief If you know the name of the class you want, find it here. + + This is a list of all Qt classes. + + \generatelist classes +*/ + +/*! + \page hierarchy.html + + \title Inheritance Hierarchy + \ingroup classlists + + \brief The C++ class inheritance hierarchy for all classes in the + Qt API. + + \generatelist classhierarchy +*/ + +/*! + \page functions.html + \title All Functions + \ingroup funclists + + \brief All documented Qt functions listed alphabetically with a + link to where each one is declared. + + This is the list of all documented member functions and global + functions in the Qt API. Each function has a link to the class or + header file where it is declared and documented. + + \generatelist functionindex +*/ + + +/*! + \page namespaces.html + \title All Namespaces + \ingroup classlists + + \brief A Qt namespace contains enum types, functions, and sometimes classes. + + This is a list of the main namespaces in Qt. + + \generatelist{namespaces} +*/ diff --git a/doc/examples.qdoc b/doc/examples.qdoc new file mode 100644 index 0000000..e5a4191 --- /dev/null +++ b/doc/examples.qdoc @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +/*! + \group qmllive-examples + \ingroup all-examples + \title QmlLive Examples + \brief Examples how to extend the functionality of QmlLive. + + \list + \o \l{contentplugin}{Content Plugin} + \endlist + +*/ diff --git a/doc/examples/contentplugin.qdoc b/doc/examples/contentplugin.qdoc new file mode 100644 index 0000000..3671309 --- /dev/null +++ b/doc/examples/contentplugin.qdoc @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +/*! + \example contentplugin + \title ContentPlugin Example + + \brief The ContentPlugin example demonstrates how to write a + Content Plugin for QmlLive + + \image contentplugin-example.png Screenshot of the Plugin in Action + + The Plugin written in this example displays Images like the + builtin Imageviewer in QmlLive, but it shows the content rotated + only works on *.png files. + + We will start by reviewing the interface defined in \c + contentadapterinterface.h in the QmlLive source code. This + interface can be used to add a new ContentAdapter to QmlLive. + The ContentAdapter will be used to display any content you want + to be handled not directly by the LiveRuntime like displaying a image. + + \snippet contentadapterinterface.h 0 + + The \c ContentAdapterInterface class declares four functions. The first + function \c canAdapt(const QUrl&) returns whether the plugin can display the + given file or directory. + + The second function \c adapt(const QUrl& url, QDeclarativeContext* context) + returns a custom QUrl which will be used by QmlLive to display the given QUrl. + The returned QUrl always has to point to a qml file used to display the content. + To be able to control the returned qml File \c context can be used to set custom + Properties which will be exported to the qml File. + + canPreview() and preview() are used for generating preview thumbnails. + We use the easiest implementation for this two methods. + + \section1 MyContentAdapterPlugin + + \snippet contentplugin/mycontentadapterplugin.h 0 + + The MyContentAdapterPlugin implements the interface to QmlLive. It subclasses + QObject and the needed \c ContentAdapterInterface. + + \snippet contentplugin/mycontentadapterplugin.h 1 + + The \c Q_INTERFACES macro will be used to register the Plugin to Qt's Plugin + System. + + + To be called only for the right file type we have to overload the + \c canAdapt(const QUrl&) function. We only want to be loaded for *.png files. + That's why we check the file ending on the given url and return true when it's + an png file. + + \snippet contentplugin/mycontentadapterplugin.cpp 0 + + If the plugin accepts the file \c adapt(const QUrl& url, QDeclarativeContext* context) + will be called. Here we export the path to the image to a special property in the + context to be able to access the fileName from within our qml File. + Afterwards we return a QUrl pointing to our qml File which is inside a ResourceFile. + + \snippet contentplugin/mycontentadapterplugin.cpp 1 + + Now only the implementation of canPreview() and preview() are missing. Here we just + add some dummy implementation because we don't want to add this functionality. + + \snippet contentplugin/mycontentadapterplugin.cpp 2 + + \section1 plugin.qml + + The plugin.qml file is our ImageViewer. In it we create a \c Image Element and + set the source to our exported Property \c imageSource. The rotation Property + will be set to 180 to rotate the Image 180 degrees. + + \snippet contentplugin/plugin.qml 0 + + \section1 The Resource File + + Because we don't want to fiddle around with paths we include our qml File into + a Resource File. The most important thing in the Resource File is to use an + unused Prefix. Otherwise our file can't be found because QmlLive also uses + Resource Files. The best approach is to use the plugin name as prefix. +*/ diff --git a/doc/images/contentplugin-example.png b/doc/images/contentplugin-example.png Binary files differnew file mode 100644 index 0000000..e298c59 --- /dev/null +++ b/doc/images/contentplugin-example.png diff --git a/doc/index.qdoc b/doc/index.qdoc new file mode 100644 index 0000000..d5d350b --- /dev/null +++ b/doc/index.qdoc @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +/*! +\page index.html +\keyword Pelagicore QML Live Reference Documentation + +\div {class="indexbox tools"} + \div {class="indexboxcont indexboxbar"} + \div {class="sectionlist normallist"} + \enddiv + \enddiv +\enddiv +\div {class="indexbox tools"} + \div {class="heading"} + Reference + \enddiv + \div {class="indexboxcont indexboxbar"} + \div {class="sectionlist normallist"} + \list + \o \l{All Classes}{All Classes} + \o \l{All Functions}{All Functions} + \endlist + \enddiv + \div {class="sectionlist normallist"} + \list + \o \l{QML Elements} + \o \l{QmlLive Examples} + \endlist + \enddiv + \enddiv +\enddiv +*/ diff --git a/doc/project.qdoc b/doc/project.qdoc new file mode 100644 index 0000000..6134891 --- /dev/null +++ b/doc/project.qdoc @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +/*! + +\page qml-live.html +\keyword QML Live +\title QML Live + +During a typical user interface design phase, designers create many graphics documents +envisioning the desired user interface. Transferring such graphical visions into +programmer’s code is difficult. Not only is it a tedious process, it often comes with great +compromises on both sides. + +Many time-consuming iterations are needed to finally reach a compromise that satisfies +the designer’s vision and is also technically feasible. However, each iteration also brings a +small change towards the goal. Qt, with the Qt Quick technology, already shortens the +gap between vision and product by introducing a more design oriented language (QML). +But there still is room for improvement... + +See also \l {usage.html} {Usage} for how to work with the QMLLiveBench + +*/ diff --git a/doc/qmllive.qdocconf b/doc/qmllive.qdocconf new file mode 100644 index 0000000..22bc41f --- /dev/null +++ b/doc/qmllive.qdocconf @@ -0,0 +1,84 @@ + +sources.fileextensions = "*.cpp *.qdoc *.mm *.qml" +headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx" +examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp *.qml" +examples.imageextensions = "*.png *.jpeg *.jpg *.gif *.mng" + +headerdirs = ../src +sourcedirs = . ../src examples + +exampledirs = ../examples \ + examples \ + ../src + +imagedirs = ../src/images \ + images + + +sourceencoding = UTF-8 +outputencoding = UTF-8 +naturallanguage = en_US + +outputdir = html + +indexes = $QTDIR/doc/html/qt.index + +project = qmllive +description = Pelagicore QML Live Reference Documentation + + +# Define the location of the templates to use. Style sheets and scripts are +# specified relative to the template directory and will be copied into +# subdirectories of the output directory. + +HTML.templatedir = template + +HTML.stylesheets = style/offline.css \ + +# Adding jquery and functions - providing online tools and search features +HTML.scripts = + + +# Files not referenced in any qdoc file. +# See also qhp.Qt.extraFiles +extraimages.HTML = images/qt-logo.png \ + images/bg_l.png \ + images/bg_l_blank.png \ + images/bg_ll_blank.png \ + images/bg_ul_blank.png \ + images/btn_next_green.png \ + images/btn_prev_green.png \ + images/header_bg.png \ + images/bg_r.png \ + images/box_bg.png \ + images/breadcrumb.png \ + images/bullet_gt.png \ + images/bullet_dn.png \ + images/bullet_sq.png \ + images/bullet_up.png \ + images/arrow_down.png \ + images/feedbackground.png \ + images/horBar.png \ + images/page.png \ + images/page_bg.png \ + images/sprites-combined.png \ + images/spinner.gif + +# Include the style sheets and scripts used. + +HTML.headerstyles = \ + " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/offline.css\" />\n" + + +qhp.projects = qmllive + +qhp.qmllive.file = qmllive.qhp +qhp.qmllive.namespace = net.pelagicore.qmllive.100 +qhp.qmllive.virtualFolder = qdoc +qhp.qmllive.indexTitle = Pelagicore QML Live Reference Documentation +qhp.qmllive.indexRoot = +qhp.qmllive.extraFiles = style/offline.css +qhp.qmllive.filterAttributes = nal network abstraction layer + + + diff --git a/doc/template/style/offline.css b/doc/template/style/offline.css new file mode 100644 index 0000000..08bfce6 --- /dev/null +++ b/doc/template/style/offline.css @@ -0,0 +1,428 @@ + +body { + color: #313131; + font: 400 14px/1.2 Arial,Helvetica; + margin-left: 5px; + margin-right: 5px; + margin-top: 85px; + text-align: justify; +} +img { + border: 2px solid #8E8D8D; + box-shadow: 3px 3px 3px #CCCCCC; + height: auto; + margin-left: 0; + max-width: 800px; +} +b { + font-weight: 600; +} +.content { +} +.descr { + margin-left: 5px; + margin-top: 35px; + min-height: 700px; + text-align: justify; + vertical-align: top; +} +.name { + font-weight: 100; + max-width: 75%; +} +tt { + text-align: left; +} +a:link { + color: #F57900; + text-align: left; + text-decoration: none; +} +a:hover { + color: #D36800; + text-align: left; + text-decoration: underline; +} +a:visited { + color: #D36800; + text-align: left; + text-decoration: none; +} +a:visited:hover { + text-align: left; + text-decoration: underline; +} +a[href*="http://"], a[href*="ftp://"], a[href*="https://"] { + background-image: url("../images/ico_out.png"); + background-position: left center; + background-repeat: no-repeat; + text-align: left; + text-decoration: none; +} +.flags { + text-decoration: none; +} +.notetitle, .tiptitle, .fastpathtitle { + font-weight: bold; +} +.attentiontitle, .cautiontitle, .dangertitle, .importanttitle, .remembertitle, .restrictiontitle { + font-weight: bold; +} +.note, .tip, .fastpath { + background: url("../images/ico_note.png") no-repeat scroll left top #F2F2F2; + border: 1px dotted #999999; + color: #666666; + margin: 5px; + padding: 5px 5px 10px 40px; +} +.attention, .caution, .danger, .important, .remember, .restriction { + background: url("../images/ico_note_attention.png") no-repeat scroll left top #F2F2F2; + border: 1px dotted #999999; + color: #666666; + margin: 5px; + padding: 5px 5px 10px 40px; +} +.header { + height: 1px; + margin: 0; + padding: 0; +} +.qtref { + display: block; + float: right; + font-size: 11px; + height: 15px; + padding-right: 10px; + position: relative; + top: -76px; + z-index: 1; +} +.naviNextPrevious { + display: block; + float: right; + height: 20px; + margin: 0; + padding-right: 10px; + padding-top: 2px; + position: relative; + text-align: right; + top: -53px; + vertical-align: top; + z-index: 1; +} +.naviNextPrevious > a.prevPage { + background-image: url("../images/btn_prev.png"); + background-position: left center; + background-repeat: no-repeat; + height: 20px; + padding-left: 20px; +} +.naviNextPrevious > a.nextPage { + background-image: url("../images/btn_next.png"); + background-position: right center; + background-repeat: no-repeat; + height: 20px; + margin-left: 30px; + padding-right: 20px; +} +.breadcrumb { + background-color: #F2F2F2; + border-bottom: 1px solid #CECECE; + display: block; + height: 20px; + margin: 0 -5px; + padding: 2px 0 0 10px; + position: relative; + top: -20px; + z-index: 1; +} +.breadcrumb ul { + margin: 0; + padding: 0; +} +.breadcrumb ul li { + background-color: #F2F2F2; + height: 20px; + list-style-type: none; + margin: 0; + padding: 0; +} +.breadcrumb li { + float: left; +} +.breadcrumb .first { + background: url("../images/home.png") no-repeat scroll left center transparent; + padding-left: 20px; +} +.breadcrumb li a { + background: url("../images/arrow.png") no-repeat scroll right center transparent; + color: #F57900; + display: block; + padding-left: 10px; + padding-right: 25px; + text-decoration: none; +} +.breadcrumb li a:hover { + background: url("../images/arrow.png") no-repeat scroll right center transparent; + color: #909090; + display: block; + padding-left: 10px; + padding-right: 20px; + text-decoration: none; +} +.title { + background-color: #E6E6E6; + border-bottom: 1px solid #CCCCCC; + border-top: 2px solid #CCCCCC; + color: #313131; + font-size: 18px; + font-weight: bold; + left: 0; + margin-left: 0; + margin-right: 0; + padding-bottom: 20px; + padding-left: 10px; + padding-top: 20px; + position: absolute; + right: 0; + top: 0; +} +h1 { + margin: 0; +} +h2, p.h2 { + background-color: #F2F3F4; + border-bottom: 1px solid #E0E0DE; + border-top: 1px solid #E0E0DE; + font: 100 16px/1.2 Arial; + margin: 30px -5px 30px -10px; + padding: 4px 4px 4px 14px; +} +h3 { + font: 100 14px/1.2 Arial; + margin-bottom: 30px; + margin-top: 30px; + text-decoration: underline; +} +h3.fn, span.fn { + background-color: #F6F6F6; + border-color: #E6E6E6; + border-radius: 7px 7px 7px 7px; + border-style: solid; + border-width: 1px; + font-size: 14px; + font-weight: bold; + margin: 30px 0 0; + max-width: 75%; + padding: 5px; + text-decoration: none; + word-spacing: 3px; +} +.name { + color: #1A1A1A; +} +.type { + color: #808080; +} +.title { + color: #F57900; + font-family: Arial,Helvetica; + font-size: 32px; + font-weight: normal; + left: 0; + position: absolute; + right: 0; + top: 0; +} +.table img { + border: medium none; + box-shadow: 0 0 0 #FFFFFF; + margin-left: 0; +} +table, pre { + background-color: #F6F6F6; + border: 1px solid #E6E6E6; + border-collapse: separate; + border-radius: 7px 7px 7px 7px; + font-size: 12px; + line-height: 1.2; + margin-bottom: 25px; + margin-left: 15px; +} +table th { + padding-left: 20px; + text-align: left; +} +table td { + border-bottom: 1px dotted #CCCCCC; + padding: 3px 15px 3px 20px; +} +table p { + margin: 0; +} +table tr.even { + background-color: white; + color: #66666E; +} +table tr.odd { + background-color: #F6F6F6; + color: #66666E; +} +table thead { + background-color: #E1E0E0; + border-left: medium none; + border-right: medium none; + padding-left: 20px; + text-align: left; +} +table thead th { + border-bottom: 2px solid #D1D1D1; + padding: 5px 10px; +} +.borderless { + background-color: #FFFFFF; + border: 1px solid #FFFFFF; + border-radius: 0 0 0 0; +} +.borderless tr { + background-color: #FFFFFF; + color: #66666E; +} +.borderless td { + -moz-border-bottom-colors: none; + -moz-border-left-colors: none; + -moz-border-right-colors: none; + -moz-border-top-colors: none; + border-color: -moz-use-text-color -moz-use-text-color #FFFFFF; + border-image: none; + border-style: none none dotted; + border-width: medium medium 1px; +} +ul { + padding-bottom: 2px; +} +li { + list-style: square outside none; + margin-bottom: 10px; + padding-left: 8px; + text-align: left; +} +ol { + margin: 10px; + padding: 0; +} +ol > li { + list-style: decimal outside none; + margin-left: 30px; + padding-left: 8px; +} +.centerAlign { + text-align: left; +} +.cpp { + display: block; + overflow: hidden; + padding: 20px 0; +} +.footer { + border-top: 1px solid #999999; + font-size: 10px; + margin-bottom: 10px; + margin-top: 50px; + padding-left: 5px; + padding-top: 11px; +} +.footerNavi { + margin-top: 50px; + text-align: right; + width: auto; + z-index: 1; +} +.memItemLeft { + padding-right: 3px; +} +.memItemRight { + padding: 3px 15px 3px 0; +} +.qml { + display: block; + overflow: hidden; + padding: 20px 0; +} +.qmldefault { + color: red; + float: right; + padding-left: 5px; +} +.qmlreadonly { + color: #254117; + float: right; + padding-left: 5px; +} +.rightAlign { + padding: 3px 5px 3px 10px; + text-align: right; +} +.toc { + background-image: url("../images/bgrContent.png"); + background-position: center top; + background-repeat: no-repeat; + float: right; + padding-bottom: 10px; + padding-top: 50px; + width: 100%; +} +.toc { + background: url("../images/bgrContent.png") repeat-x scroll center top #FFFFFF; + border: 1px solid #E6E6E6; + border-radius: 7px 7px 7px 7px; + clear: both; + float: right; + height: auto; + margin-left: 20px; + margin-right: 20px; + margin-top: 0; + padding-bottom: 10px; + padding-left: 5px; + padding-top: 0; + text-align: left; + vertical-align: top; + width: 200px; + z-index: 2; +} +.toc h3 { + text-decoration: none; +} +.toc h3 { + font: 100 14px/1.2 Arial; + margin: 0; + padding: 5px 0 0 5px; +} +.toc ul { + padding-left: 10px; + padding-right: 5px; + padding-top: 10px; + width: 160px; +} +.toc ul li { + list-style: disc outside none; + margin-left: 20px; +} +.toc ul li a:link { + color: #F57900; + text-decoration: none; +} +.toc ul li a:hover { + color: #D36800; + text-decoration: underline; +} +.toc ul li a:visited { + color: #D36800; + font-weight: bold; +} +.level1 { + border: medium none; +} +.clearfix { + clear: both; +} diff --git a/examples/contentplugin/contentplugin.pro b/examples/contentplugin/contentplugin.pro new file mode 100644 index 0000000..c142b07 --- /dev/null +++ b/examples/contentplugin/contentplugin.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +CONFIG += plugin +INCLUDEPATH += ../../src +HEADERS = mycontentadapterplugin.h +SOURCES = mycontentadapterplugin.cpp +TARGET = myContentAdapterPlugin +DESTDIR = ../../bin/plugins + +RESOURCES += res.qrc \ + res.qrc + +OTHER_FILES += \ + plugin.qml diff --git a/examples/contentplugin/mycontentadapterplugin.cpp b/examples/contentplugin/mycontentadapterplugin.cpp new file mode 100644 index 0000000..ab1a6ba --- /dev/null +++ b/examples/contentplugin/mycontentadapterplugin.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +#include "mycontentadapterplugin.h" + +#include <QtCore/QtPlugin> +#include <QtDeclarative/QDeclarativeContext> + +MyContentAdapterPlugin::MyContentAdapterPlugin(QObject *parent) : + QObject(parent) +{ +} + +//! [2] +bool MyContentAdapterPlugin::canPreview(const QString &path) const +{ + Q_UNUSED(path) + + return false; +} + +QImage MyContentAdapterPlugin::preview(const QString &path, const QSize &requestedSize) +{ + Q_UNUSED(path); + Q_UNUSED(requestedSize); + + return QImage(); +} +//! [2] + +//! [0] +bool MyContentAdapterPlugin::canAdapt(const QUrl &url) const +{ + return url.toLocalFile().endsWith(".png"); +} +//! [0] + +//! [1] +QUrl MyContentAdapterPlugin::adapt(const QUrl &url, QDeclarativeContext *context) +{ + context->setContextProperty("imageSource", url); + + return QString("qrc:/mycontentadatperplugin/plugin.qml"); +} +//! [1] + +Q_EXPORT_PLUGIN2(myContentAdapterPlugin, MyContentAdapterPlugin) diff --git a/examples/contentplugin/mycontentadapterplugin.h b/examples/contentplugin/mycontentadapterplugin.h new file mode 100644 index 0000000..2d21565 --- /dev/null +++ b/examples/contentplugin/mycontentadapterplugin.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +#ifndef MYCONTENTADAPTERPLUGIN_H +#define MYCONTENTADAPTERPLUGIN_H + +#include <contentadapterinterface.h> + +//! [0] +class MyContentAdapterPlugin : public QObject, public ContentAdapterInterface +{ + Q_OBJECT +//! [1] + Q_INTERFACES(ContentAdapterInterface) +//! [1] +public: + explicit MyContentAdapterPlugin(QObject *parent = 0); + + bool canPreview(const QString& path) const; + QImage preview(const QString& path, const QSize &requestedSize); + + bool canAdapt(const QUrl& url) const; + QUrl adapt(const QUrl& url, QDeclarativeContext* context); + +}; +//! [0] + +#endif // MYCONTENTADAPTERPLUGIN_H diff --git a/examples/contentplugin/plugin.qml b/examples/contentplugin/plugin.qml new file mode 100644 index 0000000..20b6afe --- /dev/null +++ b/examples/contentplugin/plugin.qml @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +//! [0] +import QtQuick 1.1 + +Rectangle { + width: 300 + height: 300 + + Image { + anchors.centerIn: parent + + rotation: 180 + source: imageSource + } +} +//! [0] diff --git a/examples/contentplugin/res.qrc b/examples/contentplugin/res.qrc new file mode 100644 index 0000000..4ff52f2 --- /dev/null +++ b/examples/contentplugin/res.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/mycontentadatperplugin"> + <file>plugin.qml</file> + </qresource> +</RCC> diff --git a/header.GPL3_PELAGICORE b/header.GPL3_PELAGICORE new file mode 100644 index 0000000..392b1c0 --- /dev/null +++ b/header.GPL3_PELAGICORE @@ -0,0 +1,27 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + diff --git a/icons/appicon.icns b/icons/appicon.icns Binary files differnew file mode 100644 index 0000000..036ad2e --- /dev/null +++ b/icons/appicon.icns diff --git a/icons/appicon.ico b/icons/appicon.ico Binary files differnew file mode 100644 index 0000000..9c6a591 --- /dev/null +++ b/icons/appicon.ico diff --git a/icons/appicon.rc b/icons/appicon.rc new file mode 100644 index 0000000..7675baa --- /dev/null +++ b/icons/appicon.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "appicon.ico" diff --git a/qmllive.pri b/qmllive.pri new file mode 100644 index 0000000..e0cc675 --- /dev/null +++ b/qmllive.pri @@ -0,0 +1,23 @@ +# from qtcreator.pri +defineTest(minQtVersion) { + maj = $$1 + min = $$2 + patch = $$3 + isEqual(QT_MAJOR_VERSION, $$maj) { + isEqual(QT_MINOR_VERSION, $$min) { + isEqual(QT_PATCH_VERSION, $$patch) { + return(true) + } + greaterThan(QT_PATCH_VERSION, $$patch) { + return(true) + } + } + greaterThan(QT_MINOR_VERSION, $$min) { + return(true) + } + } + greaterThan(QT_MAJOR_VERSION, $$maj) { + return(true) + } + return(false) +} diff --git a/qmllive.pro b/qmllive.pro new file mode 100644 index 0000000..bf51bb7 --- /dev/null +++ b/qmllive.pro @@ -0,0 +1,39 @@ +include(qmllive.pri) + +!minQtVersion(5, 1, 1):error("You need at least Qt 5.1.1 to build this application") + +TEMPLATE = subdirs + + +SUBDIRS += \ + src \ + # tests + +exists($(QTDIR)/bin/qdoc3) { + exists($(QTDIR)/bin/qhelpgenerator) { + message ("Using qdoc/qhelpgenerator in QTDIR for generating docs") + QDOC = $(QTDIR)/bin/qdoc3 + QHELPGENERATOR = $(QTDIR)/bin/qhelpgenerator + } else { + message ("Trying to use system qdoc/qhelpgenerator for generating docs") + QDOC = qdoc3 + QHELPGENERATOR = qhelpgenerator + } +} else { + message ("Trying to use system qdoc/qhelpgenerator for generating docs") + QDOC = qdoc3 + QHELPGENERATOR = qhelpgenerator +} + +html-docs.files = $$PWD/doc/html + +html-docs.commands = $$QDOC $$PWD/doc/qmllive.qdocconf +html-docs.files = $$PWD/doc/html + +qch-docs.commands = $$QHELPGENERATOR $$PWD/doc/html/qmllive.qhp -o $$PWD/doc/html/qmllive.qch +qch-docs.files = $$PWD/docs/qch +qch-docs.CONFIG += no_check_exist directory + +docs.depends = html-docs qch-docs + +QMAKE_EXTRA_TARGETS += html-docs qch-docs docs diff --git a/src/bench/allhostswidget.cpp b/src/bench/allhostswidget.cpp new file mode 100644 index 0000000..8ae2315 --- /dev/null +++ b/src/bench/allhostswidget.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "allhostswidget.h" + +#include <QGroupBox> +#include <QPushButton> +#include <QLabel> +#include <QMenu> +#include <QGridLayout> +#include <QDragEnterEvent> +#include <QDropEvent> +#include <QMimeData> +#include <QUrl> +#include <QMessageBox> + +AllHostsWidget::AllHostsWidget(QWidget *parent) : + QWidget(parent) +{ + setAcceptDrops(true); + + setFixedHeight(155); + + QGridLayout* layout = new QGridLayout(this); + m_groupBox = new QGroupBox("All Hosts"); + layout->addWidget(m_groupBox); + + m_menuButton = new QPushButton("...", m_groupBox); + m_menuButton->setMaximumWidth(30); + m_menuButton->setCheckable(true); + connect(m_menuButton, SIGNAL(clicked()), this, SLOT(showMenu())); + + QVBoxLayout* hbox = new QVBoxLayout(m_groupBox); + hbox->addWidget(new QLabel("Drop File")); + hbox->addWidget(m_menuButton); + + m_menu = new QMenu(this); + m_publishAction = m_menu->addAction("Publish All", this, SLOT(onPublishTriggered())); + connect(m_menu, SIGNAL(aboutToHide()), m_menuButton, SLOT(toggle())); + + m_refreshAction = m_menu->addAction("Refresh All", this, SIGNAL(refreshAll())); +} + +void AllHostsWidget::setWorkspace(const QString &workspace) +{ + m_workspace.setPath(workspace); +} + +void AllHostsWidget::showMenu() +{ + QPoint p = mapToGlobal(m_menuButton->pos()); + p.ry() += m_menuButton->height() + 5; + p.rx() += 5; + m_menu->exec(p); +} + +void AllHostsWidget::onPublishTriggered() +{ + if (QMessageBox::question(this, QString("Publish %1").arg(m_workspace.path()), + QString("Do you really want to publish the content of %1").arg(m_workspace.path())) == QMessageBox::Yes) { + emit publishAll(); + } +} + +void AllHostsWidget::dragEnterEvent(QDragEnterEvent *event) +{ + if (event->mimeData()->hasFormat("text/uri-list")) { + event->acceptProposedAction(); + } +} + +void AllHostsWidget::dropEvent(QDropEvent *event) +{ + QUrl url(event->mimeData()->text()); + + if (url.isLocalFile()) + emit currentFileChanged(url.toLocalFile()); + event->acceptProposedAction(); +} diff --git a/src/bench/allhostswidget.h b/src/bench/allhostswidget.h new file mode 100644 index 0000000..bd55db8 --- /dev/null +++ b/src/bench/allhostswidget.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QWidget> +#include <QDir> + +class QGroupBox; +class QPushButton; +class QMenu; +class AllHostsWidget : public QWidget +{ + Q_OBJECT +public: + explicit AllHostsWidget(QWidget *parent = 0); + + void setWorkspace(const QString& workspace); + +signals: + void refreshAll(); + void publishAll(); + void currentFileChanged(const QString file); + +protected: + void dropEvent(QDropEvent *event); + void dragEnterEvent(QDragEnterEvent *event); +private slots: + void showMenu(); + void onPublishTriggered(); +private: + QDir m_workspace; + QGroupBox* m_groupBox; + QPushButton* m_menuButton; + QMenu* m_menu; + QAction* m_publishAction; + QAction* m_refreshAction; +}; + diff --git a/src/bench/autodiscoveryhostsdialog.cpp b/src/bench/autodiscoveryhostsdialog.cpp new file mode 100644 index 0000000..1d1998a --- /dev/null +++ b/src/bench/autodiscoveryhostsdialog.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "autodiscoveryhostsdialog.h" +#include "ui_autodiscoveryhostsdialog.h" +#include "hostmodel.h" + +AutoDiscoveryHostsDialog::AutoDiscoveryHostsDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AutoDiscoveryHostsDialog), + m_model(0) +{ + ui->setupUi(this); +} + +AutoDiscoveryHostsDialog::~AutoDiscoveryHostsDialog() +{ + delete ui; +} + +QList<QPointer<Host> > AutoDiscoveryHostsDialog::selectedHosts() const +{ + QList<QPointer<Host> > hostList; + + QModelIndexList selectedRows = ui->hostView->selectionModel()->selectedRows(); + foreach (QModelIndex index, selectedRows) { + Host* host = m_model->hostAt(index.row()); + hostList.append(QPointer<Host>(host)); + } + + return hostList; +} + +void AutoDiscoveryHostsDialog::clearSelection() +{ + ui->hostView->clearSelection(); +} + +void AutoDiscoveryHostsDialog::setDiscoveredHostsModel(HostModel *model) +{ + m_model = model; + + ui->hostView->setModel(model); + ui->hostView->hideColumn(0); +} diff --git a/src/bench/autodiscoveryhostsdialog.h b/src/bench/autodiscoveryhostsdialog.h new file mode 100644 index 0000000..7eed8cf --- /dev/null +++ b/src/bench/autodiscoveryhostsdialog.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QDialog> +#include <QPointer> + +namespace Ui { +class AutoDiscoveryHostsDialog; +} + +class HostModel; +class Host; + +class AutoDiscoveryHostsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AutoDiscoveryHostsDialog(QWidget *parent = 0); + ~AutoDiscoveryHostsDialog(); + + QList<QPointer<Host> > selectedHosts() const; + + void clearSelection(); + + void setDiscoveredHostsModel(HostModel* model); + +private: + Ui::AutoDiscoveryHostsDialog *ui; + HostModel* m_model; +}; + diff --git a/src/bench/autodiscoveryhostsdialog.ui b/src/bench/autodiscoveryhostsdialog.ui new file mode 100644 index 0000000..58f2a4f --- /dev/null +++ b/src/bench/autodiscoveryhostsdialog.ui @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AutoDiscoveryHostsDialog</class> + <widget class="QDialog" name="AutoDiscoveryHostsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>549</width> + <height>284</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Select the Hosts you want to add:</string> + </property> + </widget> + </item> + <item> + <widget class="QTableView" name="hostView"> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + <attribute name="horizontalHeaderHighlightSections"> + <bool>false</bool> + </attribute> + <attribute name="horizontalHeaderStretchLastSection"> + <bool>true</bool> + </attribute> + <attribute name="verticalHeaderVisible"> + <bool>false</bool> + </attribute> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>AutoDiscoveryHostsDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>AutoDiscoveryHostsDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/bench/bench.pro b/src/bench/bench.pro new file mode 100644 index 0000000..ee1ef67 --- /dev/null +++ b/src/bench/bench.pro @@ -0,0 +1,61 @@ +TEMPLATE = app +TARGET = qmllivebench +DESTDIR = ../../bin + +QT *= gui core quick widgets core-private + +SOURCES += \ + main.cpp \ + mainwindow.cpp \ + optionsdialog.cpp \ + benchlivenodeengine.cpp \ + previewimageprovider.cpp \ + directorypreviewadapter.cpp \ + qmlpreviewadapter.cpp \ + benchquickview.cpp \ + host.cpp \ + hostmodel.cpp \ + hostwidget.cpp \ + dummydelegate.cpp \ + allhostswidget.cpp \ + hostmanager.cpp \ + hostsoptionpage.cpp \ + httpproxyoptionpage.cpp \ + importpathoptionpage.cpp \ + hostdiscoverymanager.cpp \ + autodiscoveryhostsdialog.cpp + +HEADERS += \ + mainwindow.h \ + optionsdialog.h \ + benchlivenodeengine.h \ + previewimageprovider.h \ + directorypreviewadapter.h \ + qmlpreviewadapter.h \ + benchquickview.h \ + host.h \ + hostmodel.h \ + hostwidget.h \ + dummydelegate.h \ + allhostswidget.h \ + hostmanager.h \ + hostsoptionpage.h \ + importpathoptionpage.h \ + httpproxyoptionpage.h \ + hostdiscoverymanager.h \ + autodiscoveryhostsdialog.h + + +FORMS += \ + optionsdialog.ui \ + hostsoptionpage.ui \ + httpproxyoptionpage.ui \ + importpathoptionpage.ui \ + autodiscoveryhostsdialog.ui + +# include(../base.pri) +include(../widgets/widgets.pri) +include(../src.pri) + +win32: RC_FILE = ../../icons/appicon.rc +osx: ICON = ../../icons/appicon.icns diff --git a/src/bench/benchlivenodeengine.cpp b/src/bench/benchlivenodeengine.cpp new file mode 100644 index 0000000..ca82016 --- /dev/null +++ b/src/bench/benchlivenodeengine.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "benchlivenodeengine.h" +#include "directorypreviewadapter.h" +#include "previewimageprovider.h" +#include "qmlpreviewadapter.h" +#include "widgets/windowwidget.h" +#include "liveruntime.h" +#include "widgets/workspaceview.h" +#include "benchquickview.h" + +#include <QFileIconProvider> +#include <QQmlImageProviderBase> + +BenchLiveNodeEngine::BenchLiveNodeEngine(QObject *parent) + : LiveNodeEngine(parent), + m_view(0), + m_ww(0), + m_workspaceView(0), + m_ignoreCache(false), + m_clipToRootObject(false) +{ + setUpdateMode(LiveNodeEngine::RecreateView); +} + +void BenchLiveNodeEngine::setWindowWidget(WindowWidget* widget) +{ + m_ww = widget; +} + +QQuickView* BenchLiveNodeEngine::initView() +{ + m_view = new BenchQuickView(); + connect(m_view, SIGNAL(sizeChanged(QSize)), this, SLOT(onSizeChanged(QSize))); + + if (!m_imageProvider) { + m_imageProvider = new PreviewImageProvider(this); + } + + m_imageProvider->setIgnoreCache(m_ignoreCache); + + m_view->engine()->addImageProvider("qmlLiveDirectoryPreview", m_imageProvider); + + emit viewChanged(m_view); + + return m_view; +} + +void BenchLiveNodeEngine::setWorkspaceView(WorkspaceView *view) +{ + m_workspaceView = view; +} + +//If a refresh is done we want to reload everything +void BenchLiveNodeEngine::refresh() +{ + m_ignoreCache = true; + reloadHelper(); +} + +//A normal reload should use the cache +void BenchLiveNodeEngine::reloadDocument() +{ + m_ignoreCache = false; + reloadHelper(); +} + +/*! + * Loads the fileIcon for the file provided by \a info and returns a QImage. + * + * It tries to resize the Icon to the \a requestedSize, but the content may be smaller. + * + * This function is used by the previewimageprovide and has to run in the mainthread. + * That's why it lives in the LiveNodeEngine + */ +QImage BenchLiveNodeEngine::convertIconToImage(const QFileInfo &info, const QSize &requestedSize) +{ + QFileIconProvider iconProvider; + QIcon icon = iconProvider.icon(info); + QImage img(requestedSize, QImage::Format_ARGB32); + img.fill(Qt::transparent); + QPainter painter(&img); + icon.paint(&painter, QRect(QPoint(0,0), requestedSize)); + return img; +} + +void BenchLiveNodeEngine::onSizeChanged(const QSize &size) +{ + m_runtime->setScreenWidth(size.width()); + m_runtime->setScreenHeight(size.height()); +} + +void BenchLiveNodeEngine::onWidthChanged(int width) +{ + m_runtime->setScreenWidth(width); +} + +void BenchLiveNodeEngine::onHeightChanged(int height) +{ + m_runtime->setScreenHeight(height); +} + +void BenchLiveNodeEngine::initPlugins() +{ + LiveNodeEngine::initPlugins(); + + DirectoryPreviewAdapter* adapter = new DirectoryPreviewAdapter(this); + if (m_workspaceView) { + //This needs to be QueuedConnection because Qt5 doesn't like it to destruct it's object while it is in a signalHandler + connect(adapter, SIGNAL(loadDocument(QString)), m_workspaceView, SLOT(activateDocument(QString)), Qt::QueuedConnection); + } + + QmlPreviewAdapter* previewAdapter = new QmlPreviewAdapter(this); + + previewAdapter->setImportPaths(importPaths()); + + m_plugins.append(adapter); + m_plugins.append(previewAdapter); + + if (m_imageProvider) + m_imageProvider->setPlugins(m_plugins); +} + +void BenchLiveNodeEngine::reloadHelper() +{ + LiveNodeEngine::reloadDocument(); + + QAbstractScrollArea* scroller = m_ww; + + ContentAdapterInterface *adapter = activePlugin(); + if (adapter && adapter->isFullScreen()) { + m_ww->setCenteringEnabled(false); + scroller->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scroller->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + } else { + m_ww->setCenteringEnabled(true); + scroller->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + scroller->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + } + m_ww->forceInitialResize(); +} diff --git a/src/bench/benchlivenodeengine.h b/src/bench/benchlivenodeengine.h new file mode 100644 index 0000000..9c19df2 --- /dev/null +++ b/src/bench/benchlivenodeengine.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include "livenodeengine.h" + +class BenchQuickView; +class WindowWidget; +class PreviewImageProvider; +class WorkspaceView; +class BenchLiveNodeEngine : public LiveNodeEngine +{ + Q_OBJECT + +public: + BenchLiveNodeEngine(QObject* parent = 0); + + void setWorkspaceView(WorkspaceView* view); + void setWindowWidget(WindowWidget *widget); + +public slots: + void refresh(); + void reloadDocument(); + +signals: + void viewChanged(BenchQuickView *view); + +protected: + void initPlugins(); + void reloadHelper(); + + virtual QQuickView* initView(); + +private Q_SLOTS: + QImage convertIconToImage(const QFileInfo& info, const QSize& requestedSize); + void onHeightChanged(int height); + void onWidthChanged(int width); + void onSizeChanged(const QSize& size); + +private: + BenchQuickView *m_view; + WindowWidget* m_ww; + QPointer<PreviewImageProvider> m_imageProvider; + WorkspaceView* m_workspaceView; + bool m_ignoreCache; + bool m_clipToRootObject; +}; diff --git a/src/bench/benchquickview.cpp b/src/bench/benchquickview.cpp new file mode 100644 index 0000000..afcfcef --- /dev/null +++ b/src/bench/benchquickview.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "benchquickview.h" +#include "QDebug" +#include "QGraphicsObject" + +BenchQuickView::BenchQuickView(QWindow *parent) : + QQuickView(parent) +{ +} + +void BenchQuickView::resizeEvent(QResizeEvent *event) +{ + emit sizeChanged(size()); + + QQuickView::resizeEvent(event); +} diff --git a/src/bench/benchquickview.h b/src/bench/benchquickview.h new file mode 100644 index 0000000..9bb9737 --- /dev/null +++ b/src/bench/benchquickview.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QQuickView> + +class BenchQuickView : public QQuickView +{ + Q_OBJECT +public: + explicit BenchQuickView(QWindow *parent = 0); + +signals: + void sizeChanged(const QSize &size); +protected: + void resizeEvent(QResizeEvent * event); + +}; diff --git a/src/bench/directorypreviewadapter.cpp b/src/bench/directorypreviewadapter.cpp new file mode 100644 index 0000000..c879308 --- /dev/null +++ b/src/bench/directorypreviewadapter.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "directorypreviewadapter.h" +#include <QFileInfo> +#include <QDir> +#include <QQmlContext> +#include <QQmlEngine> + +DirectoryPreviewAdapter::DirectoryPreviewAdapter(QObject *parent) : + QObject(parent) +{ +} + +bool DirectoryPreviewAdapter::canPreview(const QString &path) const +{ + Q_UNUSED(path); + + return false; +} + +QImage DirectoryPreviewAdapter::preview(const QString &path, const QSize &requestedSize) +{ + Q_UNUSED(path); + Q_UNUSED(requestedSize); + + return QImage(); +} + + +bool DirectoryPreviewAdapter::isFullScreen() const +{ + return true; +} + +bool DirectoryPreviewAdapter::canAdapt(const QUrl &url) const +{ + QFileInfo info(url.toLocalFile()); + return info.isDir(); +} +QUrl DirectoryPreviewAdapter::adapt(const QUrl &url, QQmlContext *context) +{ + QDir dir(url.toLocalFile()); + + context->setContextProperty("files", dir.entryList(QDir::Files | QDir::NoDotDot | QDir::NoDot | QDir::NoSymLinks)); + context->setContextProperty("path", url.toLocalFile()); + context->setContextProperty("adapter", this); + + if (availableFeatures().testFlag(QtQuickControls)) + return QUrl("qrc:/livert/folderview_qt5_controls.qml"); + + return QUrl("qrc:/livert/folderview_qt5.qml"); +} + diff --git a/src/bench/directorypreviewadapter.h b/src/bench/directorypreviewadapter.h new file mode 100644 index 0000000..fe926c8 --- /dev/null +++ b/src/bench/directorypreviewadapter.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include "contentadapterinterface.h" + +class QDeclarativeContext; +class DirectoryPreviewAdapter : public QObject, public ContentAdapterInterface +{ + Q_OBJECT + Q_INTERFACES(ContentAdapterInterface) +public: + explicit DirectoryPreviewAdapter(QObject *parent = 0); + + bool canPreview(const QString& path) const; + QImage preview(const QString& path, const QSize &requestedSize); + + bool isFullScreen() const; + + bool canAdapt(const QUrl& url) const; + virtual QUrl adapt(const QUrl& url, QQmlContext* context); + +Q_SIGNALS: + + void loadDocument(const QString& path); +}; diff --git a/src/bench/dummydelegate.cpp b/src/bench/dummydelegate.cpp new file mode 100644 index 0000000..ac7bc43 --- /dev/null +++ b/src/bench/dummydelegate.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "dummydelegate.h" + +DummyDelegate::DummyDelegate(QObject *parent) : + QItemDelegate(parent) +{ +} + +QSize DummyDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + Q_UNUSED(option) + Q_UNUSED(index) + + return QSize(280, 100); +} + +void DummyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + Q_UNUSED(painter) + Q_UNUSED(option) + Q_UNUSED(index) +} diff --git a/src/bench/dummydelegate.h b/src/bench/dummydelegate.h new file mode 100644 index 0000000..3fae85f --- /dev/null +++ b/src/bench/dummydelegate.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QItemDelegate> + +class DummyDelegate : public QItemDelegate +{ + Q_OBJECT +public: + explicit DummyDelegate(QObject *parent = 0); + + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; +}; + diff --git a/src/bench/host.cpp b/src/bench/host.cpp new file mode 100644 index 0000000..d97fd74 --- /dev/null +++ b/src/bench/host.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "host.h" +#include <QDebug> +#include <QSettings> + +Host::Host(Type type, QObject *parent) : + QObject(parent), + m_port(10234), + m_xOffset(0), + m_yOffset(0), + m_rotation(0), + m_type(type), + m_online(false), + m_followTreeSelection(false) +{ +} + +Host::Host(const Host &host, QObject *parent) : + QObject(parent), + m_name(host.name()), + m_address(host.address()), + m_port(host.port()), + m_currentFile(host.currentFile()), + m_xOffset(host.xOffset()), + m_yOffset(host.yOffset()), + m_rotation(host.rotation()), + m_type(host.type()), + m_online(host.online()), + m_followTreeSelection(host.followTreeSelection()), + m_autoDiscoveryId(host.autoDiscoveryId()), + m_productVersion(host.productVersion()), + m_systemName(host.systemName()) +{ +} + +QString Host::name() const +{ + return m_name; +} + +QString Host::address() const +{ + return m_address; +} + +QString Host::currentFile() const +{ + return m_currentFile; +} + +int Host::xOffset() const +{ + return m_xOffset; +} + +int Host::yOffset() const +{ + return m_yOffset; +} + +int Host::rotation() const +{ + return m_rotation; +} + +void Host::setName(QString arg) +{ + if (m_name != arg) { + m_name = arg; + emit nameChanged(arg); + } +} + +void Host::setAddress(QString arg) +{ + if (m_address != arg) { + m_address = arg; + emit addressChanged(arg); + } +} + +void Host::setCurrentFile(QString arg) +{ + m_currentFile = arg; + emit currentFileChanged(arg); +} + +void Host::setXOffset(int arg) +{ + if (m_xOffset != arg) { + m_xOffset = arg; + emit xOffsetChanged(arg); + } +} + +void Host::setYOffset(int arg) +{ + if (m_yOffset != arg) { + m_yOffset = arg; + emit yOffsetChanged(arg); + } +} + +void Host::setRotation(int arg) +{ + if (m_rotation != arg) { + m_rotation = arg; + emit rotationChanged(arg); + } +} + +void Host::setOnline(bool arg) +{ + if (m_online != arg) { + m_online = arg; + emit onlineChanged(arg); + } +} + +void Host::setFollowTreeSelection(bool arg) +{ + if (m_followTreeSelection != arg) { + m_followTreeSelection = arg; + emit followTreeSelectionChanged(arg); + } +} + +void Host::setAutoDiscoveryId(QUuid arg) +{ + if (m_autoDiscoveryId != arg) { + m_autoDiscoveryId = arg; + emit autoDiscoveryIdChanged(arg); + } +} + +void Host::setProductVersion(QString arg) +{ + m_productVersion = arg; +} + +void Host::setSystemName(QString arg) +{ + m_systemName = arg; +} + +void Host::setPort(int arg) +{ + if (m_port != arg) { + m_port = arg; + emit portChanged(arg); + } +} + +Host::Type Host::type() const +{ + return m_type; +} + +bool Host::online() const +{ + return m_online; +} + +bool Host::followTreeSelection() const +{ + return m_followTreeSelection; +} + +void Host::saveToSettings(QSettings *s) +{ + Q_ASSERT(s); + + s->setValue("name", name()); + s->setValue("address", address()); + s->setValue("port", port()); + s->setValue("type", type()); + s->setValue("followTreeSelection", followTreeSelection()); + s->setValue("xOffset", xOffset()); + s->setValue("yOffset", yOffset()); + s->setValue("rotation", rotation()); + s->setValue("currentFile", currentFile()); + s->setValue("autoDiscoveryId", autoDiscoveryId().toString()); + s->setValue("systemName", systemName()); + s->setValue("productVersion", productVersion()); +} + +void Host::restoreFromSettings(QSettings *s) +{ + Q_ASSERT(s); + + setName(s->value("name").toString()); + setAddress(s->value("address").toString()); + setPort(s->value("port").toInt()); + m_type = static_cast<Host::Type>(s->value("type").toInt()); + setFollowTreeSelection(s->value("followTreeSelection").toBool()); + setXOffset(s->value("xOffset").toInt()); + setYOffset(s->value("yOffset").toInt()); + setRotation(s->value("rotation").toInt()); + setCurrentFile(s->value("currentFile").toString()); + setAutoDiscoveryId(QUuid(s->value("autoDiscoveryId").toString())); + setSystemName(s->value("systemName").toString()); + setProductVersion(s->value("productVersion").toString()); +} + +QString Host::productVersion() const +{ + return m_productVersion; +} + +QString Host::systemName() const +{ + return m_systemName; +} + +QUuid Host::autoDiscoveryId() const +{ + return m_autoDiscoveryId; +} + +int Host::port() const +{ + return m_port; +} diff --git a/src/bench/host.h b/src/bench/host.h new file mode 100644 index 0000000..9db349e --- /dev/null +++ b/src/bench/host.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QObject> +#include <QUuid> +#include <QMetaType> + +class QSettings; +class Host : public QObject +{ + Q_OBJECT +public: + enum Type { + AutoDiscovery, + Manual + }; + + //If you add properties here, you maybe also have to change the hostform.ui and the hostform.h (HostChanges) + + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QString address READ address WRITE setAddress NOTIFY addressChanged) + Q_PROPERTY(int port READ port WRITE setPort NOTIFY portChanged) + Q_PROPERTY(QString currentFile READ currentFile WRITE setCurrentFile NOTIFY currentFileChanged) + Q_PROPERTY(int xOffset READ xOffset WRITE setXOffset NOTIFY xOffsetChanged) + Q_PROPERTY(int yOffset READ yOffset WRITE setYOffset NOTIFY yOffsetChanged) + Q_PROPERTY(int rotation READ rotation WRITE setRotation NOTIFY rotationChanged) + Q_PROPERTY(bool online READ online WRITE setOnline NOTIFY onlineChanged) + Q_PROPERTY(bool followTreeSelection READ followTreeSelection WRITE setFollowTreeSelection NOTIFY followTreeSelectionChanged) + Q_PROPERTY(QUuid autoDiscoveryId READ autoDiscoveryId WRITE setAutoDiscoveryId NOTIFY autoDiscoveryIdChanged) + Q_PROPERTY(QString productVersion READ productVersion WRITE setProductVersion) + Q_PROPERTY(QString systemName READ systemName WRITE setSystemName) + + explicit Host(Type type = Manual, QObject *parent = 0); + Host(const Host& host, QObject *parent = 0); + + QString name() const; + QString address() const; + int port() const; + QString currentFile() const; + int xOffset() const; + int yOffset() const; + int rotation() const; + Type type() const; + + bool online() const; + bool followTreeSelection() const; + QUuid autoDiscoveryId() const; + QString productVersion() const; + QString systemName() const; + + + void saveToSettings(QSettings *s); + void restoreFromSettings(QSettings *s); + +signals: + + void nameChanged(QString arg); + void addressChanged(QString arg); + void portChanged(int arg); + void currentFileChanged(QString arg); + void xOffsetChanged(int arg); + void yOffsetChanged(int arg); + void rotationChanged(int arg); + void onlineChanged(bool arg); + void followTreeSelectionChanged(bool arg); + void autoDiscoveryIdChanged(QUuid arg); + + +public slots: + + void setName(QString arg); + void setAddress(QString arg); + void setPort(int arg); + void setCurrentFile(QString arg); + void setXOffset(int arg); + void setYOffset(int arg); + void setRotation(int arg); + void setOnline(bool arg); + void setFollowTreeSelection(bool arg); + void setAutoDiscoveryId(QUuid arg); + void setProductVersion(QString arg); + void setSystemName(QString arg); + +private: + + QString m_name; + QString m_address; + int m_port; + QString m_currentFile; + int m_xOffset; + int m_yOffset; + int m_rotation; + Type m_type; + bool m_online; + bool m_followTreeSelection; + QUuid m_autoDiscoveryId; + QString m_productVersion; + QString m_systemName; +}; + +Q_DECLARE_METATYPE( Host* ) + diff --git a/src/bench/hostdiscoverymanager.cpp b/src/bench/hostdiscoverymanager.cpp new file mode 100644 index 0000000..db37de4 --- /dev/null +++ b/src/bench/hostdiscoverymanager.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "hostdiscoverymanager.h" +#include "hostmodel.h" + +HostDiscoveryManager::HostDiscoveryManager(QObject *parent) : + QObject(parent) , + m_discoverymodel(new HostModel(this)), + m_knownhostsmodel(0) +{ +} + +void HostDiscoveryManager::rescan() +{ +} + +void HostDiscoveryManager::setKnownHostsModel(HostModel *model) +{ + m_knownhostsmodel = model; +} + +HostModel *HostDiscoveryManager::knownHostsModel() const +{ + return m_knownhostsmodel; +} + +HostModel *HostDiscoveryManager::discoveredHostsModel() const +{ + return m_discoverymodel; +} + +void HostDiscoveryManager::deviceAdded(const QUuid &uuid, const QString &type, int version, const QString &domain) +{ + Q_UNUSED(uuid); + Q_UNUSED(type); + Q_UNUSED(version); + Q_UNUSED(domain); +} + +void HostDiscoveryManager::deviceChanged(const QUuid &uuid, const QString &type, int version, const QString &domain) +{ + Q_UNUSED(uuid); + Q_UNUSED(type); + Q_UNUSED(version); + Q_UNUSED(domain); +} + +void HostDiscoveryManager::deviceRemoved(const QUuid &uuid, const QString &type, int version, const QString &domain) +{ + Q_UNUSED(uuid); + Q_UNUSED(type); + Q_UNUSED(version); + Q_UNUSED(domain); +} + +void HostDiscoveryManager::serviceAdded(const QUuid &uuid, const QString &type, int version, const QString &domain) +{ + Q_UNUSED(uuid); + Q_UNUSED(type); + Q_UNUSED(version); + Q_UNUSED(domain);} + +void HostDiscoveryManager::serviceChanged(const QUuid &uuid, const QString &type, int version, const QString &domain) +{ + Q_UNUSED(uuid); + Q_UNUSED(type); + Q_UNUSED(version); + Q_UNUSED(domain);} + +void HostDiscoveryManager::serviceRemoved(const QUuid &uuid, const QString &type, int version, const QString &domain) +{ + Q_UNUSED(uuid); + Q_UNUSED(type); + Q_UNUSED(version); + Q_UNUSED(domain);} + +void HostDiscoveryManager::updateHostFromExtraValues(Host* host, QMap<QString, QStringList> extraValues) +{ + Q_UNUSED(host); + Q_UNUSED(extraValues); +} + +bool HostDiscoveryManager::checkExtraValues(QMap<QString, QStringList> extraValues) +{ + Q_UNUSED(extraValues); + return true; +} + +void HostDiscoveryManager::serviceAlive(const QUuid &uuid, const QString &type, int version, const QString &domain) +{ + Q_UNUSED(uuid); + Q_UNUSED(type); + Q_UNUSED(version); + Q_UNUSED(domain); +} diff --git a/src/bench/hostdiscoverymanager.h b/src/bench/hostdiscoverymanager.h new file mode 100644 index 0000000..38b23d0 --- /dev/null +++ b/src/bench/hostdiscoverymanager.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QObject> +#include <QtCore> + +class HostModel; +class Host; +class HostDiscoveryManager : public QObject +{ + Q_OBJECT +public: + explicit HostDiscoveryManager(QObject *parent = 0); + + void rescan(); + + void setKnownHostsModel(HostModel* model); + HostModel *knownHostsModel() const; + + HostModel *discoveredHostsModel() const; + +private slots: + void deviceAdded(const QUuid &uuid, const QString &type, int version, const QString &domain); + void deviceChanged(const QUuid &uuid, const QString &type, int version, const QString &domain); + void deviceRemoved(const QUuid &uuid, const QString &type, int version, const QString &domain); + + void serviceAdded(const QUuid &uuid, const QString &type, int version, const QString &domain); + void serviceChanged(const QUuid &uuid, const QString &type, int version, const QString &domain); + void serviceRemoved(const QUuid &uuid, const QString &type, int version, const QString &domain); + void serviceAlive(const QUuid &uuid, const QString &type, int version, const QString &domain); + + void updateHostFromExtraValues(Host *host, QMap<QString, QStringList> extraValues); + bool checkExtraValues(QMap<QString, QStringList> extraValues); + +private: + HostModel* m_discoverymodel; + HostModel* m_knownhostsmodel; +}; + diff --git a/src/bench/hostmanager.cpp b/src/bench/hostmanager.cpp new file mode 100644 index 0000000..678b7ec --- /dev/null +++ b/src/bench/hostmanager.cpp @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "hostmanager.h" +#include "hostmodel.h" +#include "hostwidget.h" +#include "dummydelegate.h" +#include "livehubengine.h" +#include "logreceiver.h" +#include "widgets/logview.h" +#include <QDockWidget> + +#include <QDebug> + +HostManager::HostManager(QWidget *parent) : + QListView(parent) +{ + setItemDelegate(new DummyDelegate(this)); + setFlow(QListView::LeftToRight); + setUniformItemSizes(true); + setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); + setSelectionMode(QAbstractItemView::SingleSelection); + setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + setDragEnabled(true); + setDefaultDropAction(Qt::MoveAction); + setDragDropMode(QAbstractItemView::InternalMove); + viewport()->setAcceptDrops(true); + setAcceptDrops(true); + setDropIndicatorShown(true); + + viewport()->setAutoFillBackground(false); +} + +void HostManager::setModel(HostModel *model) +{ + m_model = model; + QListView::setModel(model); + + connect(model, SIGNAL(modelReset()), this, SLOT(modelReseted())); +} + +void HostManager::setLiveHubEngine(LiveHubEngine *engine) +{ + m_engine = engine; + + for (int i=0; i < m_model->rowCount(); i++) { + HostWidget* widget = qobject_cast<HostWidget*>(indexWidget(m_model->index(i, 0))); + if (widget) + widget->setLiveHubEngine(engine); + } +} + +void HostManager::followTreeSelection(const QString ¤tFile) +{ + for (int i=0; i < m_model->rowCount(); i++) { + HostWidget* widget = qobject_cast<HostWidget*>(indexWidget(m_model->index(i, 0))); + if (widget && widget->followTreeSelection()) + widget->setCurrentFile(currentFile); + } +} + +void HostManager::setCurrentFile(const QString ¤tFile) +{ + for (int i=0; i < m_model->rowCount(); i++) { + HostWidget* widget = qobject_cast<HostWidget*>(indexWidget(m_model->index(i, 0))); + if (widget) + widget->setCurrentFile(currentFile); + } +} + +void HostManager::publishAll() +{ + for (int i=0; i < m_model->rowCount(); i++) { + HostWidget* widget = qobject_cast<HostWidget*>(indexWidget(m_model->index(i, 0))); + if (widget) + widget->publishWorkspace(); + } +} + +void HostManager::refreshAll() +{ + for (int i=0; i < m_model->rowCount(); i++) { + HostWidget* widget = qobject_cast<HostWidget*>(indexWidget(m_model->index(i, 0))); + if (widget) + widget->refresh(); + } +} + +void HostManager::rowsInserted(const QModelIndex &parent, int start, int end) +{ + if (parent.isValid()) + return; + + for (int i=start; i<= end; i++) { + addHost(i); + } +} + +void HostManager::addHost(int index) +{ + HostWidget* widget = new HostWidget(); + Host* host = m_model->hostAt(index); + widget->setLiveHubEngine(m_engine.data()); + widget->setHost(host); + setIndexWidget(m_model->index(index,0), widget); + connect(widget, SIGNAL(openHostConfig(Host*)), this, SIGNAL(openHostConfig(Host*))); + + QDockWidget* dock = new QDockWidget(host->name()); + dock->setObjectName(host->name() + "LogDock"); + connect(host, SIGNAL(nameChanged(QString)), dock, SLOT(setWindowTitle(QString))); + LogView* view = new LogView(false, dock); + connect(widget, SIGNAL(remoteLog(int,QString,QUrl,int,int)), view, SLOT(appendToLog(int,QString,QUrl,int,int))); + dock->setWidget(view); + m_logList.append(dock); + emit logWidgetAdded(dock); +} + +void HostManager::rowsAboutToBeRemoved(const QModelIndex & parent, int start, int end) +{ + if (parent.isValid()) + return; + + for (int i=start; i<= end; i++) { + QDockWidget* dock = m_logList.takeAt(i); + delete dock; + } +} + +void HostManager::modelReseted() +{ + for (int i=0; i < m_model->rowCount(); i++) { + addHost(i); + } +} diff --git a/src/bench/hostmanager.h b/src/bench/hostmanager.h new file mode 100644 index 0000000..4b6f7bb --- /dev/null +++ b/src/bench/hostmanager.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QListView> +#include <QPointer> + +class LiveHubEngine; +class HostModel; + +class QDockWidget; +class Host; +class HostManager : public QListView +{ + Q_OBJECT +public: + explicit HostManager(QWidget *parent = 0); + + void setModel(HostModel* model); + void setLiveHubEngine(LiveHubEngine* engine); + +signals: + void logWidgetAdded(QDockWidget* log); + void openHostConfig(Host* host); + +public slots: + void followTreeSelection(const QString& currentFile); + void setCurrentFile(const QString& currentFile); + void publishAll(); + void refreshAll(); + +private slots: + void rowsInserted(const QModelIndex& parent, int start, int end);\ + void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + void modelReseted(); + void addHost(int index); + +private: + QPointer<LiveHubEngine> m_engine; + + HostModel* m_model; + QList<QDockWidget*> m_logList; +}; + diff --git a/src/bench/hostmodel.cpp b/src/bench/hostmodel.cpp new file mode 100644 index 0000000..aa2cbb4 --- /dev/null +++ b/src/bench/hostmodel.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "hostmodel.h" +#include <QDebug> +#include <QIcon> +#include <QSettings> +#include <QMimeData> + +HostModel::HostModel(QObject *parent) : + QAbstractListModel(parent) +{ +} + +int HostModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + + return m_hosts.count(); +} + +int HostModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + + return 5; +} + +QVariant HostModel::data(const QModelIndex &index, int role) const +{ + if (index.row() < 0 || index.row() >= m_hosts.count()) + return QVariant(); + + Host* host = m_hosts.at(index.row()); + + switch (index.column()) { + case 0: { + switch (role) { + case NameRole: return host->name(); + case AddressRole: return host->address(); + } + break; + } + case 1: if (role == Qt::DisplayRole) return host->name(); break; + case 2: if (role == Qt::DisplayRole) return host->productVersion(); break; + case 3: if (role == Qt::DisplayRole) return host->systemName(); break; + case 4: if (role == Qt::DisplayRole) return QString("%1:%2").arg(host->address()).arg(host->port()); break; + } + + return QVariant(); +} + +QVariant HostModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Vertical) + return QVariant(); + + switch (section) { + case 0: if (role == Qt::DisplayRole) return QVariant(); + case 1: if (role == Qt::DisplayRole) return QString("Name"); + case 2: if (role == Qt::DisplayRole) return QString("Version"); + case 3: if (role == Qt::DisplayRole) return QString("System"); + case 4: if (role == Qt::DisplayRole) return QString("Ip"); + } + + return QVariant(); +} + +void HostModel::addHost(Host *host) +{ + Q_ASSERT(host); + + beginInsertRows(QModelIndex(), m_hosts.count(), m_hosts.count()); + m_hosts.append(host); + connect(host, SIGNAL(nameChanged(QString)), this, SLOT(onHostChanged())); + connect(host, SIGNAL(addressChanged(QString)), this, SLOT(onHostChanged())); + connect(host, SIGNAL(portChanged(int)), this, SLOT(onHostChanged())); + connect(host, SIGNAL(followTreeSelectionChanged(bool)), this, SLOT(onHostChanged())); + connect(host, SIGNAL(currentFileChanged(QString)), this, SLOT(onHostChanged())); + connect(host, SIGNAL(xOffsetChanged(int)), this, SLOT(onHostChanged())); + connect(host, SIGNAL(yOffsetChanged(int)), this, SLOT(onHostChanged())); + connect(host, SIGNAL(rotationChanged(int)), this, SLOT(onHostChanged())); + connect(host, SIGNAL(onlineChanged(bool)), this, SLOT(onHostChanged())); + + endInsertRows(); +} + +void HostModel::removeHost(Host *host) +{ + int idx = m_hosts.indexOf(host); + + if (idx == -1) + return; + + beginRemoveRows(QModelIndex(), idx, idx); + Host *item = m_hosts.takeAt(idx); + delete item; + endRemoveRows(); +} + +void HostModel::removeHost(int index) +{ + if (index < 0 || index >= m_hosts.count()) + return; + + beginRemoveRows(QModelIndex(), index, index); + Host *item = m_hosts.takeAt(index); + delete item; + endRemoveRows(); +} + +int HostModel::indexOf(Host *host) +{ + return m_hosts.indexOf(host); +} + +void HostModel::clear() +{ + beginResetModel(); + qDeleteAll(m_hosts); + m_hosts.clear(); + endResetModel(); +} + +QList<Host *> HostModel::findByAutoDiscoveryId(QUuid id) const +{ + QList<Host* > hosts; + foreach (Host* host, m_hosts) { + if (host->autoDiscoveryId() == id) + hosts.append(host); + } + + return hosts; +} + +Host *HostModel::hostAt(int index) const +{ + if (index < 0 || index >= m_hosts.count()) + return 0; + + return m_hosts.at(index); +} + +void HostModel::onHostChanged() +{ + Host* host = qobject_cast<Host*>(sender()); + + if (host) { + int idx = m_hosts.indexOf(host); + if (idx != -1) { + emit dataChanged(index(idx, 0), index(idx, 3)); + } + } +} + +void HostModel::restoreFromSettings(QSettings *s) +{ + Q_ASSERT(s); + + beginResetModel(); + qDeleteAll(m_hosts); + m_hosts.clear(); + + s->beginGroup("AllHosts"); + int size = s->beginReadArray("host"); + + for (int i=0; i < size; i++) { + s->setArrayIndex(i); + Host* host = new Host(Host::AutoDiscovery, this); + host->restoreFromSettings(s); + m_hosts.append(host); + } + + s->endArray(); + s->endGroup(); + + endResetModel(); +} + +void HostModel::saveToSettings(QSettings *s) +{ + Q_ASSERT(s); + + s->beginGroup("AllHosts"); + s->beginWriteArray("host", m_hosts.size()); + + int i=0; + foreach (Host* host, m_hosts) { + s->setArrayIndex(i++); + host->saveToSettings(s); + } + + s->endArray(); + s->endGroup(); +} + +bool HostModel::removeRows ( int row, int count, const QModelIndex & parent) +{ + if (row < 0 || row >= m_hosts.count() || parent.isValid()) + return false; + + beginRemoveRows(QModelIndex(), row, row + count -1); + for (int i=0; i<count; i++) { + Host *item = m_hosts.takeAt(row + i); + delete item; + } + endRemoveRows(); + + return true; +} + +bool HostModel::dropMimeData(const QMimeData *data, + Qt::DropAction action, int row, int column, const QModelIndex &parent) +{ + if (action == Qt::IgnoreAction) + return true; + + if (!data->hasFormat("application/x-qabstractitemmodeldatalist")) + return false; + + if (column > 0) + return false; + + if (row < 0) + return false; + + if (parent.isValid()) + return false; + + QByteArray encoded = data->data("application/x-qabstractitemmodeldatalist"); + QDataStream stream(&encoded, QIODevice::ReadOnly); + + while (!stream.atEnd()) + { + int sourceRow, sourceCol; + QMap<int, QVariant> roleDataMap; + stream >> sourceRow >> sourceCol >> roleDataMap; + + if (sourceRow == row -1 || sourceRow == row) + return false; + + beginMoveRows(QModelIndex(), sourceRow, sourceRow, QModelIndex(), row); + m_hosts.move(sourceRow, (row - sourceRow) > 0 ? row - 1 : row); + endMoveRows(); + + return true; + } + + return false; +} + +Qt::DropActions HostModel::supportedDropActions() const +{ + return Qt::MoveAction; +} + +Qt::ItemFlags HostModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index); + + if (index.isValid()) + return Qt::ItemIsDragEnabled | defaultFlags; + else + return Qt::ItemIsDropEnabled | defaultFlags; +} diff --git a/src/bench/hostmodel.h b/src/bench/hostmodel.h new file mode 100644 index 0000000..6b22a62 --- /dev/null +++ b/src/bench/hostmodel.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QAbstractListModel> +#include "host.h" + +class QSettings; +class HostModel : public QAbstractListModel +{ + Q_OBJECT +public: + + enum HostRoles { + NameRole = Qt::UserRole, + AddressRole + }; + + explicit HostModel(QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + + void addHost(Host* host); + void removeHost(Host* host); + void removeHost(int index); + int indexOf(Host* host); + void clear(); + + QList<Host*> findByAutoDiscoveryId(QUuid id) const; + + Host* hostAt(int index) const; + + void restoreFromSettings(QSettings* s); + void saveToSettings(QSettings* s); + + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); +protected: + Qt::DropActions supportedDropActions() const; + Qt::ItemFlags flags(const QModelIndex &index) const; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + +private slots: + void onHostChanged(); +private: + QList<Host*> m_hosts; +}; + diff --git a/src/bench/hostsoptionpage.cpp b/src/bench/hostsoptionpage.cpp new file mode 100644 index 0000000..17e4a7c --- /dev/null +++ b/src/bench/hostsoptionpage.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "hostsoptionpage.h" +#include "ui_hostsoptionpage.h" +#include "hostmodel.h" +#include "autodiscoveryhostsdialog.h" + +#include <QMenu> +#include <QDebug> + +HostsOptionsPage::HostsOptionsPage(QWidget *parent) : + QWidget(parent), + ui(new Ui::HostsOptionPage), + m_currentIndex(-1), + m_model(0), + m_autoDiscoveryDialog(new AutoDiscoveryHostsDialog(this)) +{ + ui->setupUi(this); + + ui->hostUI->setVisible(false); + + connect(ui->nameField, SIGNAL(textEdited(QString)), this, SLOT(updateName(QString))); + connect(ui->ipField, SIGNAL(textEdited(QString)), this, SLOT(updateAddress(QString))); + connect(ui->portField, SIGNAL(valueChanged(int)), this, SLOT(updatePort(int))); + connect(ui->followTreeSelectionField, SIGNAL(clicked(bool)), this, SLOT(updateFollowTreeSelection(bool))); + connect(ui->xField, SIGNAL(valueChanged(int)), this, SLOT(updateXOffset(int))); + connect(ui->yField, SIGNAL(valueChanged(int)), this, SLOT(updateYOffset(int))); + connect(ui->rotationField, SIGNAL(valueChanged(int)), this, SLOT(updateRotation(int))); + + QMenu* menu = new QMenu(ui->addHostButton); + menu->addAction("Auto Discovery...", this, SLOT(showAutoDiscoveryDialog())); + menu->addAction("Manual", this, SLOT(addHost())); + ui->addHostButton->setMenu(menu); + + connect(ui->removeHostButton, SIGNAL(clicked()), this, SLOT(removeHost())); +} + +HostsOptionsPage::~HostsOptionsPage() +{ + delete ui; +} + +void HostsOptionsPage::setHostModel(HostModel *model) +{ + m_model = model; + m_currentIndex = -1; + + connect(ui->hostsWidget->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), + this, SLOT(onCurrentRowChanged(QModelIndex,QModelIndex))); + + for (int i=0; i< m_model->rowCount(); i++) { + Host* host = m_model->hostAt(i); + addHost(host); + } +} + +void HostsOptionsPage::setDiscoveredHostsModel(HostModel *model) +{ + m_autoDiscoveryDialog->setDiscoveredHostsModel(model); +} + +void HostsOptionsPage::apply() +{ + for (int i=0; i < ui->hostsWidget->rowCount(); i++) { + QTableWidgetItem* item = ui->hostsWidget->item(i, 0); + Host* host = item->data(Qt::UserRole).value<Host*>(); + if (ui->hostsWidget->isRowHidden(i)) { + if (host) + m_model->removeHost(host); + continue; + } + + host->setName(item->text()); + host->setAddress(item->data(Qt::UserRole + 1).toString()); + host->setPort(item->data(Qt::UserRole + 2).toInt()); + host->setFollowTreeSelection(item->data(Qt::UserRole + 4).toBool()); + host->setXOffset(item->data(Qt::UserRole + 5).toInt()); + host->setYOffset(item->data(Qt::UserRole + 6).toInt()); + host->setRotation(item->data(Qt::UserRole + 7).toInt()); + + if (m_model->indexOf(host) == -1) + m_model->addHost(host); + } + + m_currentIndex = -1; +} + +void HostsOptionsPage::setHostSelected(Host *host) +{ + ui->hostsWidget->selectRow(m_model->indexOf(host)); +} + +void HostsOptionsPage::onCurrentRowChanged ( const QModelIndex & current, const QModelIndex & previous ) +{ + Q_UNUSED(previous); + + if (!current.isValid()) { + ui->hostUI->setVisible(false); + m_currentIndex = -1; + } + + ui->removeHostButton->setEnabled(true); + + m_currentIndex = current.row(); + + QTableWidgetItem* typeItem = ui->hostsWidget->item(m_currentIndex, 1); + + QString type = typeItem->text(); + bool autoDiscovery = (type == "Auto"); + + QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0); + + ui->nameField->setText(item->text()); + ui->typeField->setText(type); + + ui->ipField->setText(item->data(Qt::UserRole + 1).toString()); + ui->portField->setValue(item->data(Qt::UserRole + 2).toInt()); + ui->ipLabel->setDisabled(autoDiscovery); + ui->ipField->setDisabled(autoDiscovery); + ui->portLabel->setDisabled(autoDiscovery); + ui->portField->setDisabled(autoDiscovery); + + ui->followTreeSelectionField->setChecked(item->data(Qt::UserRole + 4).toBool()); + + ui->xField->setValue(item->data(Qt::UserRole + 5).toInt()); + ui->yField->setValue(item->data(Qt::UserRole + 6).toInt()); + ui->rotationField->setValue(item->data(Qt::UserRole + 7).toInt()); + + ui->hostUI->setVisible(true); +} + +void HostsOptionsPage::updateName(const QString &name) +{ + Q_ASSERT(m_currentIndex != -1); + + ui->hostsWidget->item(m_currentIndex, 0)->setText(name); +} + +void HostsOptionsPage::updateAddress(const QString &address) +{ + Q_ASSERT(m_currentIndex != -1); + + QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0); + + ui->hostsWidget->item(m_currentIndex, 2)->setText(QString("%1:%2").arg(address).arg(item->data(Qt::UserRole + 2).toInt())); + + item->setData(Qt::UserRole + 1, address); +} + +void HostsOptionsPage::updatePort(int port) +{ + Q_ASSERT(m_currentIndex != -1); + + QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0); + + ui->hostsWidget->item(m_currentIndex, 2)->setText(QString("%1:%2").arg(item->data(Qt::UserRole + 1).toString()).arg(port)); + + item->setData(Qt::UserRole + 2, port); +} + +void HostsOptionsPage::updateFollowTreeSelection(bool enabled) +{ + Q_ASSERT(m_currentIndex != -1); + + QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0); + + item->setData(Qt::UserRole + 4, enabled); +} + +void HostsOptionsPage::updateXOffset(int offset) +{ + Q_ASSERT(m_currentIndex != -1); + + QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0); + + item->setData(Qt::UserRole + 5, offset); +} + +void HostsOptionsPage::updateYOffset(int offset) +{ + Q_ASSERT(m_currentIndex != -1); + + QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0); + + item->setData(Qt::UserRole + 6, offset); +} + +void HostsOptionsPage::updateRotation(int rotation) +{ + Q_ASSERT(m_currentIndex != -1); + + QTableWidgetItem* item = ui->hostsWidget->item(m_currentIndex, 0); + + item->setData(Qt::UserRole + 7, rotation); +} + +void HostsOptionsPage::addHost(Host *host) +{ + if (!host) + host = new Host(Host::Manual, m_model); + + int count = ui->hostsWidget->rowCount(); + ui->hostsWidget->setRowCount(count + 1); + + QTableWidgetItem* item = new QTableWidgetItem(host->name()); + ui->hostsWidget->setItem(count, 0, item); + + item->setData(Qt::UserRole, QVariant::fromValue(host)); + item->setData(Qt::UserRole + 1, host->address()); + item->setData(Qt::UserRole + 2, host->port()); + item->setData(Qt::UserRole + 4, host->followTreeSelection()); + item->setData(Qt::UserRole + 5, host->xOffset()); + item->setData(Qt::UserRole + 6, host->yOffset()); + item->setData(Qt::UserRole + 7, host->rotation()); + + ui->hostsWidget->setItem(count, 1, new QTableWidgetItem(host->type() == Host::AutoDiscovery ? "Auto" : "Manual")); + ui->hostsWidget->setItem(count, 2, new QTableWidgetItem(QString("%1:%2").arg(host->address()).arg(host->port()))); +} + +void HostsOptionsPage::removeHost() +{ + if (m_currentIndex == -1) + return; + + ui->hostsWidget->hideRow(m_currentIndex); + + ui->hostsWidget->clearSelection(); + ui->hostUI->setVisible(false); + ui->removeHostButton->setEnabled(false); + m_currentIndex = -1; +} + +void HostsOptionsPage::showAutoDiscoveryDialog() +{ + m_autoDiscoveryDialog->clearSelection(); + if (m_autoDiscoveryDialog->exec()) { + QList<QPointer<Host> > hostList = m_autoDiscoveryDialog->selectedHosts(); + foreach (QPointer<Host> host, hostList) { + if (!host) + continue; + + addHost(new Host(*host, m_model)); + } + } +} diff --git a/src/bench/hostsoptionpage.h b/src/bench/hostsoptionpage.h new file mode 100644 index 0000000..c4a1b2e --- /dev/null +++ b/src/bench/hostsoptionpage.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QWidget> +#include <QModelIndex> + +namespace Ui { +class HostsOptionPage; +} + +class Host; +class HostModel; +class QMenu; +class AutoDiscoveryHostsDialog; + +class HostsOptionsPage : public QWidget +{ + Q_OBJECT + +public: + explicit HostsOptionsPage(QWidget *parent = 0); + ~HostsOptionsPage(); + + void setHostModel(HostModel* model); + void setDiscoveredHostsModel(HostModel* model); + + void apply(); + + void setHostSelected(Host* host); + +private slots: + void onCurrentRowChanged(const QModelIndex ¤t, const QModelIndex &previous); + + void updateName(const QString& name); + void updateAddress(const QString& address); + void updatePort(int port); + void updateFollowTreeSelection(bool enabled); + void updateXOffset(int offset); + void updateYOffset(int offset); + void updateRotation(int rotation); + + void addHost(Host* host = 0); + void removeHost(); + + void showAutoDiscoveryDialog(); + +private: + Ui::HostsOptionPage *ui; + + int m_currentIndex; + HostModel* m_model; + AutoDiscoveryHostsDialog* m_autoDiscoveryDialog; +}; + diff --git a/src/bench/hostsoptionpage.ui b/src/bench/hostsoptionpage.ui new file mode 100644 index 0000000..dc77d21 --- /dev/null +++ b/src/bench/hostsoptionpage.ui @@ -0,0 +1,276 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>HostsOptionPage</class> + <widget class="QWidget" name="HostsOptionPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>390</width> + <height>546</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QTableWidget" name="hostsWidget"> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::SingleSelection</enum> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + <property name="columnCount"> + <number>3</number> + </property> + <attribute name="horizontalHeaderHighlightSections"> + <bool>false</bool> + </attribute> + <attribute name="horizontalHeaderStretchLastSection"> + <bool>true</bool> + </attribute> + <attribute name="verticalHeaderVisible"> + <bool>false</bool> + </attribute> + <attribute name="verticalHeaderHighlightSections"> + <bool>false</bool> + </attribute> + <column> + <property name="text"> + <string>Name</string> + </property> + </column> + <column> + <property name="text"> + <string>Type</string> + </property> + </column> + <column> + <property name="text"> + <string>IP</string> + </property> + </column> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QToolButton" name="addHostButton"> + <property name="text"> + <string>Add</string> + </property> + <property name="popupMode"> + <enum>QToolButton::InstantPopup</enum> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + <property name="arrowType"> + <enum>Qt::NoArrow</enum> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="removeHostButton"> + <property name="text"> + <string>Remove</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> + </item> + </layout> + </item> + <item> + <widget class="QFrame" name="hostUI"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QFormLayout" name="formLayout_2"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::ExpandingFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="nameLabel"> + <property name="text"> + <string>Name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="nameField"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="typeLabel"> + <property name="text"> + <string>Type:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="typeField"> + <property name="text"> + <string>Auto</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="ipLabel"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>IP:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLineEdit" name="ipField"/> + </item> + <item> + <widget class="QLabel" name="portLabel"> + <property name="text"> + <string>Port:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="portField"> + <property name="maximum"> + <number>99999</number> + </property> + </widget> + </item> + </layout> + </item> + <item row="3" column="0" colspan="2"> + <widget class="QCheckBox" name="followTreeSelectionField"> + <property name="text"> + <string>Follow Tree Selection</string> + </property> + </widget> + </item> + <item row="5" column="0" colspan="2"> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Remote Setup</string> + </property> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::ExpandingFieldsGrow</enum> + </property> + <item row="2" column="0"> + <widget class="QLabel" name="xLabel"> + <property name="text"> + <string>X:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QSpinBox" name="xField"> + <property name="maximum"> + <number>99999</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="yLabel"> + <property name="text"> + <string>Y:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="yField"> + <property name="maximum"> + <number>99999</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="rotationLabel"> + <property name="text"> + <string>Rotation:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <item> + <widget class="QSpinBox" name="rotationField"> + <property name="minimum"> + <number>-360</number> + </property> + <property name="maximum"> + <number>360</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/bench/hostwidget.cpp b/src/bench/hostwidget.cpp new file mode 100644 index 0000000..2c41373 --- /dev/null +++ b/src/bench/hostwidget.cpp @@ -0,0 +1,431 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "hostwidget.h" + +#include <QGroupBox> +#include <QLabel> +#include <QFormLayout> +#include <QGridLayout> +#include <QPushButton> +#include <QDropEvent> +#include <QDragEnterEvent> +#include <QMimeData> +#include <QProgressBar> +#include <QMenu> +#include <QMessageBox> +#include <QInputDialog> +#include <QToolButton> +#include <QDebug> + +#include "host.h" +#include "livehubengine.h" + +HostWidget::HostWidget(QWidget *parent) : + QWidget(parent) +{ + setAcceptDrops(true); + + setFixedHeight(155); + + QGridLayout* layout = new QGridLayout(this); + m_groupBox = new QGroupBox(); + layout->addWidget(m_groupBox); + + QVBoxLayout* vbox = new QVBoxLayout(m_groupBox); + QFormLayout* formLayout = new QFormLayout(); + formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + m_ipLabel = new QLabel(m_groupBox); + m_fileLabel = new QLabel(m_groupBox); + m_statusLabel = new QLabel(m_groupBox); + + formLayout->addRow("IP:", m_ipLabel); + formLayout->addRow("File:", m_fileLabel); + formLayout->addRow("Status:",m_statusLabel); + + m_groupBox->installEventFilter(this); + + vbox->addLayout(formLayout); + + m_sendProgress = new QProgressBar(m_groupBox); + m_sendProgress->setMaximum(1); + m_sendProgress->setValue(1); + m_menuButton = new QToolButton(m_groupBox); + m_menuButton->setText("..."); + m_menuButton->setMinimumWidth(35); + m_menuButton->setPopupMode(QToolButton::InstantPopup); + m_menuButton->setCheckable(true); + + QHBoxLayout* hbox = new QHBoxLayout(); + hbox->addWidget(m_sendProgress); + hbox->addWidget(m_menuButton); + + vbox->addLayout(hbox); + + + m_menu = new QMenu(this); + m_connectDisconnectAction = m_menu->addAction("Connect", this, SLOT(connectAndSendFile())); + m_refreshAction = m_menu->addAction("Refresh", this, SLOT(refresh())); + m_publishAction = m_menu->addAction("Publish All", this, SLOT(publishAll())); + m_followTreeSelectionAction = m_menu->addAction("Follow Tree Selection"); + m_followTreeSelectionAction->setCheckable(true); + m_editHostAction = m_menu->addAction("Edit Host", this, SLOT(onEditHost())); + + m_menuButton->setMenu(m_menu); + + connect(&m_publisher, SIGNAL(connected()), this, SIGNAL(connected())); + connect(&m_publisher, SIGNAL(connected()), this, SLOT(onConnected())); + connect(&m_publisher, SIGNAL(disconnected()), this, SLOT(onDisconnected())); + connect(&m_publisher, SIGNAL(connectionError(QAbstractSocket::SocketError)), + this, SLOT(onConnectionError(QAbstractSocket::SocketError))); + connect(&m_publisher, SIGNAL(sendingError(QUuid,QAbstractSocket::SocketError)), + this, SLOT(onSendingError(QUuid,QAbstractSocket::SocketError))); + connect(&m_publisher, SIGNAL(sentSuccessfully(QUuid)), + this, SLOT(onSentSuccessfully(QUuid))); + connect(&m_publisher, SIGNAL(needsPinAuthentication()), this, SLOT(showPinDialog())); + connect(&m_publisher, SIGNAL(pinOk(bool)), this, SLOT(onPinOk(bool))); + connect(&m_publisher, SIGNAL(remoteLog(int,QString,QUrl,int,int)), + this, SIGNAL(remoteLog(int,QString,QUrl,int,int))); + + onDisconnected(); +} + +void HostWidget::setHost(Host *host) +{ + m_host = host; + + updateName(m_host->name()); + updateIp(m_host->address()); + updateFile(m_host->currentFile()); + updateOnlineState(m_host->online()); + m_followTreeSelectionAction->setChecked(m_host->followTreeSelection()); + + connect(host, SIGNAL(addressChanged(QString)), this, SLOT(updateIp(QString))); + connect(host, SIGNAL(portChanged(int)), this, SLOT(updatePort(int))); + connect(host, SIGNAL(onlineChanged(bool)), this, SLOT(updateOnlineState(bool))); + connect(host, SIGNAL(currentFileChanged(QString)), this, SLOT(updateFile(QString))); + connect(host, SIGNAL(nameChanged(QString)), this, SLOT(updateName(QString))); + connect(host, SIGNAL(xOffsetChanged(int)), this, SLOT(sendXOffset(int))); + connect(host, SIGNAL(yOffsetChanged(int)), this, SLOT(sendYOffset(int))); + connect(host, SIGNAL(rotationChanged(int)), this, SLOT(sendRotation(int))); + connect(host, SIGNAL(followTreeSelectionChanged(bool)), + m_followTreeSelectionAction, SLOT(setChecked(bool))); + + connect(m_followTreeSelectionAction, SIGNAL(triggered(bool)), host, SLOT(setFollowTreeSelection(bool))); +} + +void HostWidget::setLiveHubEngine(LiveHubEngine *engine) +{ + m_engine = engine; + + m_publisher.setWorkspace(m_engine->workspace()); + + connect(m_engine.data(), SIGNAL(workspaceChanged(QString)), &m_publisher, SLOT(setWorkspace(QString))); + connect(m_engine.data(), SIGNAL(fileChanged(QString)), this, SLOT(sendDocument(QString))); +} + +void HostWidget::setCurrentFile(const QString currentFile) +{ + m_host->setCurrentFile(currentFile); +} + +bool HostWidget::followTreeSelection() const +{ + return m_followTreeSelectionAction->isChecked(); +} + +void HostWidget::updateName(const QString &name) +{ + m_groupBox->setTitle(name); +} + +void HostWidget::updateIp(const QString &ip) +{ + m_ipLabel->setText(QString("%1:%2").arg(ip).arg(m_host->port())); + + QTimer::singleShot(0, this, SLOT(connectToServer())); +} + +void HostWidget::updatePort(int port) +{ + m_ipLabel->setText(QString("%1:%2").arg(m_host->address()).arg(port)); + + QTimer::singleShot(0, this, SLOT(connectToServer())); +} + +void HostWidget::updateFile(const QString &file) +{ + QString relFile = QDir(m_engine->workspace()).relativeFilePath(file); + setUpdateFile(relFile); + m_fileLabel->setToolTip(relFile); + + connectAndSendFile(); +} + +void HostWidget::setUpdateFile(const QString &file) +{ + QFontMetrics metrics(font()); + m_fileLabel->setText(metrics.elidedText(file, Qt::ElideLeft, m_fileLabel->width())); +} + +void HostWidget::updateOnlineState(bool online) +{ + qDebug() << "updateOnline"; + + bool available = online || m_host->type() == Host::Manual; + + if (available) + QTimer::singleShot(0, this, SLOT(connectToServer())); + else + onDisconnected(); +} + +void HostWidget::connectToServer() +{ + qDebug() << "connectToServer"; + + if (m_publisher.state() == QAbstractSocket::ConnectedState || m_publisher.state() == QAbstractSocket::ConnectingState) { + return; + } + + if (m_host->online() || m_host->type() == Host::Manual) { + m_publisher.connectToServer(m_host->address(), m_host->port()); + m_activateId = QUuid(); + m_rotationId = QUuid(); + m_xOffsetId = QUuid(); + m_yOffsetId = QUuid(); + m_changeIds.clear(); + } +} + +void HostWidget::connectAndSendFile() +{ + connectToServer(); + m_activateId = m_publisher.activateDocument(QDir(m_engine->workspace()).relativeFilePath(m_host->currentFile())); +} + +void HostWidget::onConnected() +{ + m_statusLabel->setPixmap(QPixmap(":/images/icon_online.png")); + m_statusLabel->setToolTip("Host online"); + + sendXOffset(m_host->xOffset()); + sendYOffset(m_host->yOffset()); + sendRotation(m_host->rotation()); + + m_connectDisconnectAction->setText("Disconnect"); + disconnect(m_connectDisconnectAction, SIGNAL(triggered()), 0, 0); + connect(m_connectDisconnectAction, SIGNAL(triggered()), &m_publisher, SLOT(disconnectFromServer())); +} + +void HostWidget::onDisconnected() +{ + m_statusLabel->setPixmap(QPixmap(":/images/icon_offline.png")); + m_statusLabel->setToolTip("Host offline"); + + m_connectDisconnectAction->setText("Connect"); + disconnect(m_connectDisconnectAction, SIGNAL(triggered()), 0, 0); + connect(m_connectDisconnectAction, SIGNAL(triggered()), this, SLOT(connectToServer())); +} + +void HostWidget::onConnectionError(QAbstractSocket::SocketError error) +{ + m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png")); + m_statusLabel->setToolTip(m_publisher.errorToString(error)); + + if (error == QAbstractSocket::RemoteHostClosedError) + m_host->setOnline(false); + + if (m_publisher.state() != QAbstractSocket::ConnectedState) + onDisconnected(); +} + +void HostWidget::refresh() +{ + connectAndSendFile(); +} + +void HostWidget::publishWorkspace() +{ + connectToServer(); + connect(m_engine.data(), SIGNAL(publishFile(QString)), this, SLOT(sendDocument(QString))); + m_engine->publishWorkspace(); + disconnect(m_engine.data(), SIGNAL(publishFile(QString)), this, SLOT(sendDocument(QString))); +} + +void HostWidget::sendDocument(const QString& document) +{ + if (m_publisher.state() != QAbstractSocket::ConnectedState) + return; + + m_changeIds.append(m_publisher.sendDocument(document)); + m_sendProgress->setMaximum(m_sendProgress->maximum() + 1); +} + +void HostWidget::sendXOffset(int offset) +{ + m_xOffsetId = m_publisher.setXOffset(offset); +} + +void HostWidget::sendYOffset(int offset) +{ + m_yOffsetId = m_publisher.setYOffset(offset); +} + +void HostWidget::sendRotation(int rotation) +{ + m_rotationId = m_publisher.setRotation(rotation); +} + +void HostWidget::onSendingError(const QUuid &uuid, QAbstractSocket::SocketError socketError) +{ + if (uuid == m_activateId) { + m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png")); + m_statusLabel->setToolTip(QString("Activating file failed: %1").arg(m_publisher.errorToString(socketError))); + m_activateId = QUuid(); + } else if (uuid == m_xOffsetId) { + m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png")); + m_statusLabel->setToolTip(QString("Setting the X Offset failed: %1").arg(m_publisher.errorToString(socketError))); + m_xOffsetId = QUuid(); + } else if (uuid == m_yOffsetId) { + m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png")); + m_statusLabel->setToolTip(QString("Setting the Y Offset failed: %1").arg(m_publisher.errorToString(socketError))); + m_yOffsetId = QUuid(); + } else if (uuid == m_rotationId) { + m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png")); + m_statusLabel->setToolTip(QString("Setting the Rotation failed: %1").arg(m_publisher.errorToString(socketError))); + m_rotationId = QUuid(); + }else if (m_changeIds.contains(uuid)) { + m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png")); + m_statusLabel->setToolTip(QString("Not all files were synced successfully: %1").arg(m_publisher.errorToString(socketError))); + m_changeIds.removeAll(uuid); + resetProgressBar(); + } +} + +void HostWidget::onSentSuccessfully(const QUuid &uuid) +{ + if (uuid == m_activateId) { + m_statusLabel->setPixmap(QPixmap(":/images/icon_online.png")); + m_activateId = QUuid(); + } else if (uuid == m_xOffsetId) { + m_statusLabel->setPixmap(QPixmap(":/images/icon_online.png")); + m_xOffsetId = QUuid(); + } else if (uuid == m_yOffsetId) { + m_statusLabel->setPixmap(QPixmap(":/images/icon_online.png")); + m_yOffsetId = QUuid(); + } else if (uuid == m_rotationId) { + m_statusLabel->setPixmap(QPixmap(":/images/icon_online.png")); + m_rotationId = QUuid(); + } else if (m_changeIds.contains(uuid)) { + m_changeIds.removeAll(uuid); + m_sendProgress->setValue(m_sendProgress->value() + 1); + if (m_changeIds.isEmpty()) { + m_statusLabel->setPixmap(QPixmap(":/images/icon_online.png")); + resetProgressBar(); + } + } +} + +void HostWidget::resetProgressBar() +{ + m_sendProgress->setValue(1); + m_sendProgress->setMaximum(1); +} + +void HostWidget::onPinOk(bool ok) +{ + if (!ok) { + m_publisher.disconnectFromServer(); + m_statusLabel->setPixmap(QPixmap(":/images/icon_failover.png")); + m_statusLabel->setToolTip("The Host didn't accept your pin"); + QMessageBox::warning(this, "Pin not accepted", "The Host didn't accept your pin"); + } +} + +void HostWidget::publishAll() +{ + if (QMessageBox::question(this, QString("Publish %1").arg(m_engine->workspace()), + QString("Do you really want to publish the content of %1").arg(m_engine->workspace())) == QMessageBox::Yes) { + publishWorkspace(); + } +} + +void HostWidget::onEditHost() +{ + emit openHostConfig(m_host); +} + +void HostWidget::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + + setUpdateFile(m_fileLabel->toolTip()); +} + +void HostWidget::showPinDialog() +{ + bool ok = false; + int pin = QInputDialog::getInt(this, "The Host needs a Pin Authentication", "Pin", 0, 0, 9999, 1, &ok); + + if (!ok) + m_publisher.disconnectFromServer(); + + m_publisher.checkPin(QString::number(pin)); +} + +void HostWidget::dragEnterEvent(QDragEnterEvent *event) +{ + if (event->mimeData()->hasFormat("text/uri-list") && (m_host->online() || m_host->type() == Host::Manual)) { + + event->acceptProposedAction(); + } +} + +void HostWidget::dropEvent(QDropEvent *event) +{ + QUrl url(event->mimeData()->text()); + + if (url.isLocalFile()) + m_host->setCurrentFile(url.toLocalFile()); + event->acceptProposedAction(); +} + +bool HostWidget::eventFilter(QObject *object, QEvent *event) +{ + if ((event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonPress) && object == m_groupBox) { + + event->ignore(); + + return true; + } + + return false; +} diff --git a/src/bench/hostwidget.h b/src/bench/hostwidget.h new file mode 100644 index 0000000..1725eb1 --- /dev/null +++ b/src/bench/hostwidget.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QWidget> +#include <QPointer> +#include <remotepublisher.h> + +class QLabel; +class QGroupBox; +class QProgressBar; +class QPushButton; +class QToolButton; +class QMenu; +class Host; +class HostWidget : public QWidget +{ + Q_OBJECT +public: + + explicit HostWidget(QWidget *parent = 0); + + void setHost(Host* host); + void setLiveHubEngine(LiveHubEngine* engine); + void setCurrentFile(const QString currentFile); + bool followTreeSelection() const; + +signals: + void connected(); + void openHostConfig(Host*); + void remoteLog(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1); + +public slots: + void publishWorkspace(); + void refresh(); + +protected: + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); + bool eventFilter(QObject *, QEvent *); + +private slots: + void updateName(const QString& name); + void updateIp(const QString& ip); + void updatePort(int port); + void updateFile(const QString& file); + void setUpdateFile(const QString& file); + void updateOnlineState(bool online); + + void connectToServer(); + void connectAndSendFile(); + + void onConnected(); + void onDisconnected(); + void onConnectionError(QAbstractSocket::SocketError error); + + void sendDocument(const QString &document); + + void sendXOffset(int offset); + void sendYOffset(int offset); + void sendRotation(int rotation); + + void onSentSuccessfully(const QUuid &uuid); + void onSendingError(const QUuid &uuid, QAbstractSocket::SocketError socketError); + void resetProgressBar(); + + void showPinDialog(); + void onPinOk(bool ok); + + void publishAll(); + void onEditHost(); + + void resizeEvent( QResizeEvent * event ); +private: + + QGroupBox* m_groupBox; + QLabel* m_ipLabel; + QLabel* m_fileLabel; + QLabel* m_statusLabel; + QProgressBar* m_sendProgress; + QToolButton* m_menuButton; + QMenu* m_menu; + QAction* m_publishAction; + QAction* m_followTreeSelectionAction; + QAction* m_refreshAction; + QAction* m_connectDisconnectAction; + QAction* m_editHostAction; + + QPointer<Host> m_host; + + RemotePublisher m_publisher; + QPointer<LiveHubEngine> m_engine; + + QUuid m_activateId; + QList<QUuid> m_changeIds; + QUuid m_xOffsetId; + QUuid m_yOffsetId; + QUuid m_rotationId; +}; + diff --git a/src/bench/httpproxyoptionpage.cpp b/src/bench/httpproxyoptionpage.cpp new file mode 100644 index 0000000..e9acc65 --- /dev/null +++ b/src/bench/httpproxyoptionpage.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "httpproxyoptionpage.h" +#include "ui_httpproxyoptionpage.h" +#include <QtNetwork> + +HttpProxyOptionPage::HttpProxyOptionPage(QWidget *parent) : + QWidget(parent), + ui(new Ui::HttpProxyOptionPage) +{ + ui->setupUi(this); + QSettings s; + ui->proxyGroup->setChecked(s.value("http_proxy/enabled").toBool()); + ui->serverField->setText(s.value("http_proxy/hostname").toString()); + ui->portField->setText(s.value("http_proxy/port").toString()); + ui->userField->setText(s.value("http_proxy/username").toString()); + ui->passwordField->setText(s.value("http_proxy/password").toString()); +} + +HttpProxyOptionPage::~HttpProxyOptionPage() +{ + delete ui; +} + +void HttpProxyOptionPage::apply() +{ + bool enabled = ui->proxyGroup->isChecked(); + QString hostname = ui->serverField->text(); + int port = ui->portField->text().toInt(); + QString username = ui->userField->text(); + QString password = ui->passwordField->text(); + if (enabled) { + QNetworkProxy proxy; + proxy.setType(QNetworkProxy::HttpProxy); + proxy.setHostName(hostname); + proxy.setPort(port); + proxy.setUser(username); + proxy.setPassword(password); + QNetworkProxy::setApplicationProxy(proxy); + } else { + QNetworkProxy::setApplicationProxy(QNetworkProxy()); + } + QSettings s; + s.setValue("http_proxy/enabled", enabled); + s.setValue("http_proxy/hostname", hostname); + s.setValue("http_proxy/port", port); + s.setValue("http_proxy/username", username); + s.setValue("http_proxy/password", password); + +} diff --git a/src/bench/httpproxyoptionpage.h b/src/bench/httpproxyoptionpage.h new file mode 100644 index 0000000..8ff0db8 --- /dev/null +++ b/src/bench/httpproxyoptionpage.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> +#include <QtGui> + +#include <QtWidgets> + + +namespace Ui { +class HttpProxyOptionPage; +} + +class HttpProxyOptionPage : public QWidget +{ + Q_OBJECT + +public: + explicit HttpProxyOptionPage(QWidget *parent = 0); + ~HttpProxyOptionPage(); + void apply(); +private: + Ui::HttpProxyOptionPage *ui; +}; diff --git a/src/bench/httpproxyoptionpage.ui b/src/bench/httpproxyoptionpage.ui new file mode 100644 index 0000000..f0c0b04 --- /dev/null +++ b/src/bench/httpproxyoptionpage.ui @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>HttpProxyOptionPage</class> + <widget class="QWidget" name="HttpProxyOptionPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="proxyGroup"> + <property name="title"> + <string>HTTP Proxy</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Server Address:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="serverField"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Port:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="portField"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Username:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="userField"/> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Password:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="passwordField"/> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>98</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/bench/importpathoptionpage.cpp b/src/bench/importpathoptionpage.cpp new file mode 100644 index 0000000..fd95a3e --- /dev/null +++ b/src/bench/importpathoptionpage.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "importpathoptionpage.h" +#include "ui_importpathoptionpage.h" + +ImportPathOptionPage::ImportPathOptionPage(QWidget *parent) : + QWidget(parent), + ui(new Ui::ImportPathOptionPage) +{ + ui->setupUi(this); + QSettings s; + int count = s.beginReadArray("imports"); + QListWidgetItem* item; + for (int i=0; i<count; i++) { + s.setArrayIndex(i); + item = new QListWidgetItem(s.value("path").toString()); + item->setFlags(item->flags () | Qt::ItemIsEditable); + ui->importList->addItem(item); + } + s.endArray(); + + connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addItem())); + connect(ui->removeButton, SIGNAL(clicked()), this, SLOT(removeItem())); + connect(ui->editButton, SIGNAL(clicked()), this, SLOT(editItem())); +} + +ImportPathOptionPage::~ImportPathOptionPage() +{ + delete ui; +} + +void ImportPathOptionPage::apply() +{ + QStringList paths; + QSettings s; + s.beginWriteArray("imports"); + for (int i=0; i<ui->importList->count(); i++) { + QString path(ui->importList->item(i)->text()); + paths << path; + s.setArrayIndex(i); + s.setValue("path", path); + } + s.endArray(); +} + +void ImportPathOptionPage::addItem() +{ + QString path = QFileDialog::getExistingDirectory(this, "Add Import Path"); + if (path.isEmpty()) { + return; + } + QListWidgetItem* item = new QListWidgetItem(path); + item->setFlags(item->flags () | Qt::ItemIsEditable); + ui->importList->addItem(item); +} + +void ImportPathOptionPage::removeItem() +{ + QListWidgetItem *item = ui->importList->currentItem(); + if (item) { + delete item; + } +} + +void ImportPathOptionPage::editItem() +{ + QListWidgetItem *item = ui->importList->currentItem(); + if (item) { + ui->importList->editItem(item); + } +} diff --git a/src/bench/importpathoptionpage.h b/src/bench/importpathoptionpage.h new file mode 100644 index 0000000..0ee307e --- /dev/null +++ b/src/bench/importpathoptionpage.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> +#include <QtGui> +#include <QtWidgets> + +namespace Ui { +class ImportPathOptionPage; +} + +class ImportPathOptionPage : public QWidget +{ + Q_OBJECT + +public: + explicit ImportPathOptionPage(QWidget *parent = 0); + ~ImportPathOptionPage(); + void apply(); +private slots: + void addItem(); + void removeItem(); + void editItem(); + +private: + Ui::ImportPathOptionPage *ui; +}; diff --git a/src/bench/importpathoptionpage.ui b/src/bench/importpathoptionpage.ui new file mode 100644 index 0000000..d5ec42f --- /dev/null +++ b/src/bench/importpathoptionpage.ui @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ImportPathOptionPage</class> + <widget class="QWidget" name="ImportPathOptionPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QListWidget" name="importList"/> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QPushButton" name="addButton"> + <property name="text"> + <string>Add</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="editButton"> + <property name="text"> + <string>Edit</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="removeButton"> + <property name="text"> + <string>Remove</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> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/bench/main.cpp b/src/bench/main.cpp new file mode 100644 index 0000000..7eeddcc --- /dev/null +++ b/src/bench/main.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include <QtGui> +#include <QtWidgets> + +#include "mainwindow.h" + + +struct Options +{ + Options() + : stayontop(false) + {} + + QString activeDocument; + QString workspace; + QString pluginPath; + QStringList importPaths; + bool stayontop; +}; + +static Options options; + +static void usage() +{ + qWarning("Usage qmllivebench [options] <workspace> <file.qml>"); + qWarning("Usage qmllivebench [options] <workspace/file.qml>"); + qWarning(" "); + qWarning(" options:"); + qWarning(" -pluginpath ........................path to qmllive plugins"); + qWarning(" -importpath ........................path to the qml import path"); + qWarning(" -stayontop .........................keep viewer window on top"); + qWarning(" "); + exit(1); +} + +static void parseArguments(const QStringList& arguments) +{ + for (int i = 1; i < arguments.count(); ++i) { + bool lastArg = (i == arguments.count() - 1); + QString arg = arguments.at(i); + + if (arg == QLatin1String("-pluginpath")) { + if (lastArg || arguments.at(++i).startsWith(QLatin1Char('-'))) usage(); + options.pluginPath = arguments.at(i);; + continue; + } else if (arg == QLatin1String("-importpath")) { + if (lastArg || arguments.at(++i).startsWith(QLatin1Char('-'))) usage(); + options.importPaths.append(QDir(arguments.at(i)).absolutePath()); + continue; + } else if (arg == QLatin1String("-stayontop")) { + options.stayontop = true; + continue; + } else if (arg.startsWith(QLatin1Char('-'))) { + usage(); + return; + } + + if (arg.endsWith(".qml")) { + qDebug() << "Found argument ending with \".qml\". Assuming it's a file."; + if (options.workspace.isEmpty()) { + qDebug() << "No workspace is set yet, assuming it's the whole path"; + QFileInfo fi(arg); + + options.workspace = fi.path(); + + if (!fi.exists()) { + qWarning() << "File does not exist: " << arg << " trying to set workspace anyway..."; + } + else { + options.activeDocument = fi.absoluteFilePath(); + } + } + else { + QFileInfo fi(arg); + if (!fi.exists()) + qWarning() << "File does not exist: " << arg << "ignoring it."; + else + options.activeDocument = fi.absoluteFilePath(); + } + } + else { + options.workspace = arg; + } + } +} + +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + app.setApplicationName("QmlLiveBench"); + app.setOrganizationDomain("pelagicore.com"); + app.setOrganizationName("Pelagicore"); + app.setAttribute(Qt::AA_NativeWindows, true); + app.setAttribute(Qt::AA_ImmediateWidgetCreation, true); + parseArguments(app.arguments()); + + //qDebug () << "apply settings..."; + MainWindow win; + if (!options.workspace.isEmpty()) { + //qDebug() << "set workspace: " << options.workspace; + win.setWorkspace(QDir(options.workspace).absolutePath()); + } + if (!options.pluginPath.isEmpty()) { + //qDebug() << "set pluginPath: " << options.pluginPath; + win.setPluginPath(QDir(options.pluginPath).absolutePath()); + } + if (!options.importPaths.isEmpty()) { + //qDebug() << "set importPaths: " << options.importPaths; + win.setImportPaths(options.importPaths); + } + if (!options.activeDocument.isEmpty()) { + //qDebug() << "set active document: " << options.activeDocument; + win.activateDocument(options.activeDocument); + } + + if (options.stayontop) + win.setStaysOnTop(true); + + win.readSettings(); + + win.show(); + + return app.exec(); +} diff --git a/src/bench/mainwindow.cpp b/src/bench/mainwindow.cpp new file mode 100644 index 0000000..f009379 --- /dev/null +++ b/src/bench/mainwindow.cpp @@ -0,0 +1,455 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "mainwindow.h" +#include "widgets/windowwidget.h" + +#include <QToolBar> +#include <QtNetwork> +#include <private/qabstractanimation_p.h> + +#include "widgets/workspaceview.h" +#include "widgets/logview.h" +#include "livehubengine.h" +#include "benchlivenodeengine.h" +#include "qmlhelper.h" +#include "optionsdialog.h" +#include "benchquickview.h" +#include "hostmodel.h" +#include "hostmanager.h" +#include "allhostswidget.h" +#include "hostdiscoverymanager.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , m_qmlview(0) + , m_workspace(new WorkspaceView()) + , m_log(new LogView(true, this)) + , m_hostManager(new HostManager(this)) + , m_hostModel(new HostModel(this)) + , m_discoveryManager(new HostDiscoveryManager(this)) + , m_allHosts(new AllHostsWidget(this)) + , m_hub(new LiveHubEngine(this)) + , m_node(new BenchLiveNodeEngine(this)) +{ + setupContent(); + setupMenuBar(); + setupToolBar(); + + m_discoveryManager->setKnownHostsModel(m_hostModel);\ + + m_hostManager->setModel(m_hostModel); + m_hostManager->setLiveHubEngine(m_hub); + + setWindowIcon(QIcon("://images/favicon.png")); + + m_hub->setFilePublishingActive(true); + m_node->setWorkspaceView(m_workspace); + + connect(m_workspace, SIGNAL(pathActivated(QString)), m_hub, SLOT(setActivePath(QString))); + connect(m_workspace, SIGNAL(pathActivated(QString)), m_hostManager, SLOT(followTreeSelection(QString))); + connect(m_hub, SIGNAL(activateDocument(QString)), this, SLOT(updateWindowTitle())); + connect(m_hub, SIGNAL(activateDocument(QString)), m_node, SLOT(setActiveDocument(QString))); + connect(m_node, SIGNAL(viewChanged(BenchQuickView*)), this, SLOT(initView(BenchQuickView*))); + connect(m_allHosts, SIGNAL(publishAll()), m_hostManager, SLOT(publishAll())); + connect(m_allHosts, SIGNAL(currentFileChanged(QString)), m_hostManager, SLOT(setCurrentFile(QString))); + connect(m_allHosts, SIGNAL(refreshAll()), m_hostManager, SLOT(refreshAll())); + connect(m_hostManager, SIGNAL(logWidgetAdded(QDockWidget*)), this, SLOT(onLogWidgetAdded(QDockWidget*))); + connect(m_hostManager, SIGNAL(openHostConfig(Host*)), this, SLOT(openPreferences(Host*))); + + BenchQuickView view; + m_qmlDefaultimportList = view.engine()->importPathList(); +} + +MainWindow::~MainWindow() +{ +} + + +void MainWindow::setupContent() +{ + setupLogView(); + setupWorkspaceView(); + setupHostView(); + + m_ww = new WindowWidget(this); + m_ww->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_ww->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_ww->setBackgroundRole(QPalette::Dark); + m_node->setWindowWidget(m_ww); + + setCentralWidget(m_ww); +} + +void MainWindow::initView(BenchQuickView *view) +{ + m_qmlview = view; + + m_ww->setCenteringEnabled(true); + m_ww->setHostedWindow(m_qmlview); + + connect(m_qmlview->engine(), SIGNAL(quit()), this, SLOT(logQuitEvent())); +} + +void MainWindow::onLogWidgetAdded(QDockWidget *logDock) +{ + m_logDockMenu->addAction(logDock->toggleViewAction()); + + logDock->setFeatures(m_logDock->features()); + logDock->setAllowedAreas(m_logDock->allowedAreas()); + addDockWidget(dockWidgetArea(m_logDock), logDock); + tabifyDockWidget(m_logDock, logDock); +} + +void MainWindow::setupWorkspaceView() +{ + m_workspaceDock = new QDockWidget("Workspace", this); + m_workspaceDock->setObjectName("workspace"); + m_workspaceDock->setWidget(m_workspace); + m_workspaceDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + m_workspaceDock->setFeatures(QDockWidget::AllDockWidgetFeatures); + addDockWidget(Qt::LeftDockWidgetArea, m_workspaceDock); +} + +void MainWindow::setupHostView() +{ + m_hostDock = new QDockWidget("Hosts", this); + m_hostDock->setObjectName("hosts"); + m_hostDock->setFeatures(QDockWidget::AllDockWidgetFeatures); + + QFrame* hostContainer = new QFrame(); + hostContainer->setFrameStyle(QFrame::StyledPanel); + QHBoxLayout* layout = new QHBoxLayout(hostContainer); + QVBoxLayout* vbox = new QVBoxLayout(); + vbox->addWidget(m_allHosts); + vbox->addStretch(1); + layout->addLayout(vbox); + layout->addWidget(m_hostManager); + layout->setContentsMargins(0,0,0,0); + + m_hostDock->setWidget(hostContainer); + addDockWidget(Qt::TopDockWidgetArea, m_hostDock); +} + +void MainWindow::setupLogView() +{ + m_logDock = new QDockWidget("Log Output", this); + m_logDock->setObjectName("log"); + m_logDock->setWidget(m_log); + m_logDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); + m_logDock->setFeatures(QDockWidget::AllDockWidgetFeatures); + addDockWidget(Qt::BottomDockWidgetArea, m_logDock); + + connect(m_node, SIGNAL(logClear()), m_log, SLOT(clear())); + connect(m_node, SIGNAL(logIgnoreMessages(bool)), m_log, SLOT(setIgnoreMessages(bool))); + connect(m_node, SIGNAL(logErrors(QList<QQmlError>)), m_log, SLOT(appendToLog(QList<QQmlError>))); +} + +void MainWindow::setupMenuBar() +{ + QMenu *file = menuBar()->addMenu(tr("&File")); + m_openWorkspace = file->addAction(QIcon::fromTheme("folder-open"), tr("&Open Workspace..."), this, SLOT(openWorkspace()), QKeySequence::Open); + m_recentMenu = file->addMenu(QIcon::fromTheme("document-open-recent"), "&Recent"); + m_recentMenu->setEnabled(false); + file->addAction(tr("Preferences..."), this, SLOT(openPreferences()), QKeySequence::Preferences); + file->addSeparator(); + file->addAction(QIcon::fromTheme("application-exit"), tr("&Quit"), this, SLOT(close()), QKeySequence::Quit); + + QMenu *view = menuBar()->addMenu(tr("&View")); + view->addAction(tr("Take Snapshot"), this, SLOT(takeSnapshot()), QKeySequence("Ctrl+F3")); + view->addSeparator(); + + QAction *slow = view->addAction(tr("Slow Down Animations"), this, SLOT(slowDownAnimations(bool)), QKeySequence(tr("Ctrl+."))); + slow->setCheckable(true); + view->addSeparator(); + + m_refresh = view->addAction(QIcon::fromTheme("view-refresh"), tr("Refresh"), m_node, SLOT(refresh()), QKeySequence::Refresh); + m_enablePluginReload = view->addAction("Reload QML Plugins"); + m_enablePluginReload->setCheckable(true); + connect(m_enablePluginReload, SIGNAL(toggled(bool)), m_node, SLOT(setReloadPluginsEnabled(bool))); + + m_resizeFit = view->addAction(QIcon::fromTheme("zoom-fit-best"), tr("Resize to Fit"), this, SLOT(resizeToFit())); + view->addAction(tr("Show Containing Folder"), m_workspace, SLOT(goUp()), QKeySequence("Ctrl+Esc")); + m_stayOnTop = view->addAction(tr("Stay on Top"), this, SLOT(stayOnTop())); + m_stayOnTop->setCheckable(true); + + view->addSeparator(); + view->addAction(m_workspaceDock->toggleViewAction()); + m_hostDock->close(); + view->addAction(m_hostDock->toggleViewAction()); + m_logDockMenu = view->addMenu("Logs"); + m_logDockMenu->addAction(m_logDock->toggleViewAction()); +} + +void MainWindow::readSettings() +{ + QSettings s; + restoreGeometry(s.value("geometry").toByteArray()); + //Only set the workspace if we didn't already set it by command line + if (m_hub->workspace() == QDir::currentPath()) + setWorkspace(s.value("workspace").toString()); + + if (s.value("http_proxy/enabled").toBool()) { + QNetworkProxy proxy; + proxy.setType(QNetworkProxy::HttpProxy); + proxy.setHostName(s.value("http_proxy/hostname").toString()); + proxy.setPort(s.value("http_proxy/port").toInt()); + proxy.setUser(s.value("http_proxy/username").toString()); + proxy.setPassword(s.value("http_proxy/password").toString()); + QNetworkProxy::setApplicationProxy(proxy); + } else { + QNetworkProxy::setApplicationProxy(QNetworkProxy()); + } + + int size = s.beginReadArray("recentFolder"); + for (int i = 0; i < size; i++) { + s.setArrayIndex(i); + m_recentFolder.append(s.value("folder").toString()); + } + s.endArray(); + + updateRecentFolder(); + + //Only set the workspace if we didn't already set it by command line + if (m_workspace->activeDocument().isEmpty()) { + if (s.contains("activeDocument")) + activateDocument(s.value("activeDocument").toString()); + else + m_workspace->activateRootPath(); + } + + resetImportPaths(); + + m_hostModel->restoreFromSettings(&s); + restoreState(s.value("windowState").toByteArray()); +} + +void MainWindow::writeSettings() +{ + QSettings s; + s.setValue("geometry", saveGeometry()); + s.setValue("windowState", saveState()); + s.setValue("workspace", m_hub->workspace()); + s.setValue("activeDocument", m_node->activeDocument().toLocalFile()); + + s.beginWriteArray("recentFolder"); + for (int i = 0; i < m_recentFolder.count(); i++) { + s.setArrayIndex(i); + s.setValue("folder", m_recentFolder.at(i)); + } + s.endArray(); + + m_hostModel->saveToSettings(&s); +} + +void MainWindow::resetImportPaths() +{ + QStringList importPaths; + QSettings s; + int count = s.beginReadArray("imports"); + for (int i=0; i<count; i++) { + s.setArrayIndex(i); + importPaths.append(s.value("path").toString()); + } + s.endArray(); + + setImportPaths(importPaths); +} + +void MainWindow::setupToolBar() +{ + m_toolBar = addToolBar("ToolBar"); + m_toolBar->setObjectName("toolbar"); + m_toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_toolBar->addAction(m_openWorkspace); + m_toolBar->addSeparator(); + m_toolBar->addAction(m_refresh); + m_toolBar->addAction(m_resizeFit); + m_toolBar->addAction(m_enablePluginReload); +} + +void MainWindow::activateDocument(const QString path) +{ + m_workspace->activateDocument(path); +} + +void MainWindow::resizeToFit() +{ + QSize diff = m_ww->sizeHint() - m_ww->rect().size(); + resize(rect().size() + diff); + updateWindowTitle(); +} + +void MainWindow::takeSnapshot() +{ + QImage img; + img = m_qmlview->grabWindow(); + + if (img.isNull()) { + m_log->appendToLog(LogView::InternalError, tr("QmlLive: could not retrieve snapshot pixmap")); + } else { + static int counter = 1; + QString fileName = QString::fromLatin1("snapshot%1.png").arg(counter++); + bool ok = img.save(fileName); + + if (!ok) // log + m_log->appendToLog(LogView::InternalError, tr("QmlLive: could not save snapshot as \"%1\"").arg(fileName)); + else + m_log->appendToLog(LogView::InternalInfo, tr("QmlLive: created snapshot \"%1\"").arg(fileName)); + } +} + +void MainWindow::slowDownAnimations(bool enable) +{ + QUnifiedTimer::instance()->setSlowModeEnabled(enable); +} + + +void MainWindow::setWorkspace(const QString& path) +{ + m_workspace->setRootPath(path); + m_node->setWorkspace(path); + m_hub->setWorkspace(path); + m_allHosts->setWorkspace(path); + updateRecentFolder(path); +} + +void MainWindow::setPluginPath(const QString &path) +{ + m_node->setPluginPath(path); +} + +void MainWindow::setImportPaths(const QStringList &pathList) +{ + m_node->setImportPaths(pathList + m_qmlDefaultimportList); +} + +void MainWindow::setStaysOnTop(bool enabled) +{ + m_stayOnTop->setChecked(enabled); + stayOnTop(); +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + writeSettings(); + QMainWindow::closeEvent(event); +} + +void MainWindow::showEvent(QShowEvent *event) +{ + QMainWindow::showEvent(event); + raise(); +} + +void MainWindow::openWorkspace() +{ + QString path = QFileDialog::getExistingDirectory(this, "Open Workspace"); + if (path.isEmpty()) { + return; + } + setWorkspace(path); +} + +void MainWindow::logQuitEvent() +{ + m_log->appendToLog(LogView::InternalInfo, tr("Qml Viewer tries to quit.")); +} + +void MainWindow::updateWindowTitle() +{ + setWindowFilePath(QString()); + if (m_hub->activePath().isEmpty()) { + setWindowTitle(QApplication::applicationName()); + } else { + setWindowTitle(QString()); + setWindowFilePath(m_hub->activePath()); + } +} + +void MainWindow::openPreferences(Host* host) +{ + OptionsDialog dialog; + dialog.setHostModel(m_hostModel); + dialog.setDiscoveredHostsModel(m_discoveryManager->discoveredHostsModel()); + + if (host) + dialog.openHostConfig(host); + if (dialog.exec()) { + resetImportPaths(); + m_discoveryManager->rescan(); + } +} + +void MainWindow::clearRecentFolder() +{ + m_recentFolder.clear(); + m_recentMenu->setEnabled(false); + updateRecentFolder(); +} + +void MainWindow::openRecentFolder() +{ + if (QAction* action = qobject_cast<QAction*>(sender())) { + setWorkspace(action->text()); + } +} + +void MainWindow::updateRecentFolder(const QString& path) +{ + if (!path.isEmpty()) + m_recentFolder.prepend(path); + m_recentFolder.removeDuplicates(); + + if (m_recentFolder.count()) + m_recentMenu->setEnabled(true); + + while (m_recentFolder.count() > 7) + m_recentFolder.removeAt(m_recentFolder.count() - 1); + + m_recentMenu->clear(); + foreach (const QString file, m_recentFolder) { + m_recentMenu->addAction(file, this, SLOT(openRecentFolder())); + } + + m_recentMenu->addSeparator(); + m_recentMenu->addAction("Clear Menu", this, SLOT(clearRecentFolder())); +} + +void MainWindow::stayOnTop() +{ + Qt::WindowFlags flags = windowFlags(); + if (m_stayOnTop->isChecked()) { + setWindowFlags(flags | Qt::WindowStaysOnTopHint); + } else { + setWindowFlags(flags ^ (Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint)); + } + show(); +} diff --git a/src/bench/mainwindow.h b/src/bench/mainwindow.h new file mode 100644 index 0000000..430bd1d --- /dev/null +++ b/src/bench/mainwindow.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> +#include <QtWidgets> +#include <QtQuick> + + +class BenchQuickView; +class WorkspaceView; +class LogView; +class LiveRuntime; +class LiveHubEngine; +class BenchLiveNodeEngine; +class WindowWidget; +class QToolBar; +class HostModel; +class HostManager; +class AllHostsWidget; +class Host; +class HostDiscoveryManager; + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + void activateDocument(const QString path); + void setWorkspace(const QString& path); + void setPluginPath(const QString& path); + void setImportPaths(const QStringList& pathList); + void setStaysOnTop(bool enabled); + void readSettings(); +protected: + void closeEvent(QCloseEvent *event); + void showEvent(QShowEvent *event); +private: + void setupContent(); + void setupWorkspaceView(); + void setupHostView(); + void setupLogView(); + void setupToolBar(); + void setupMenuBar(); + void writeSettings(); + void resetImportPaths(); +private slots: + void resizeToFit(); + void takeSnapshot(); + void slowDownAnimations(bool enable); + void openWorkspace(); + void logQuitEvent(); + void updateWindowTitle(); + void openPreferences(Host *host = 0); + void openRecentFolder(); + void clearRecentFolder(); + void stayOnTop(); + + void initView(BenchQuickView *view); + + void onLogWidgetAdded(QDockWidget* logDock); + +private: + void updateRecentFolder(const QString &path = QString()); + BenchQuickView *m_qmlview; + WindowWidget *m_ww; + WorkspaceView *m_workspace; + LogView *m_log; + QUrl m_currentSource; + QDockWidget *m_logDock; + QDockWidget *m_workspaceDock; + QDockWidget *m_hostDock; + HostManager *m_hostManager; + HostModel *m_hostModel; + HostDiscoveryManager *m_discoveryManager; + AllHostsWidget* m_allHosts; + LiveHubEngine *m_hub; + BenchLiveNodeEngine *m_node; + QStringList m_recentFolder; + QMenu* m_recentMenu; + QMenu* m_logDockMenu; + QAction *m_stayOnTop; + QAction *m_openWorkspace; + QAction *m_refresh; + QAction *m_resizeFit; + QAction *m_enablePluginReload; + QAction *m_clipRootObject; + QToolBar* m_toolBar; + QStringList m_qmlDefaultimportList; +}; diff --git a/src/bench/optionsdialog.cpp b/src/bench/optionsdialog.cpp new file mode 100644 index 0000000..439725c --- /dev/null +++ b/src/bench/optionsdialog.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "optionsdialog.h" +#include "ui_optionsdialog.h" +#include "httpproxyoptionpage.h" +#include "importpathoptionpage.h" +#include "hostsoptionpage.h" + +OptionsDialog::OptionsDialog(QWidget *parent) + : QDialog(parent) + , ui(new Ui::OptionsDialog) + , m_httpProxyForm(new HttpProxyOptionPage(this)) + , m_importPathsForm(new ImportPathOptionPage(this)) + , m_hostsForm(new HostsOptionsPage(this)) +{ + ui->setupUi(this); + + QListWidgetItem* item = new QListWidgetItem("HTTP Proxy"); + int index = ui->optionsStack->addWidget(m_httpProxyForm); + item->setSelected(true); + item->setData(Qt::UserRole, index); + ui->optionsView->addItem(item); + + item = new QListWidgetItem("Import Paths"); + index = ui->optionsStack->addWidget(m_importPathsForm); + item->setData(Qt::UserRole, index); + ui->optionsView->addItem(item); + + item = new QListWidgetItem("Hosts"); + index = ui->optionsStack->addWidget(m_hostsForm); + item->setData(Qt::UserRole, index); + ui->optionsView->addItem(item); + + connect(ui->optionsView, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(optionSelected(QListWidgetItem*))); +} + +OptionsDialog::~OptionsDialog() +{ + delete ui; +} + +void OptionsDialog::setHostModel(HostModel *model) +{ + m_hostsForm->setHostModel(model); +} + +void OptionsDialog::setDiscoveredHostsModel(HostModel *model) +{ + m_hostsForm->setDiscoveredHostsModel(model); +} + +void OptionsDialog::openHostConfig(Host *host) +{ + ui->optionsView->setCurrentRow(2); + m_hostsForm->setHostSelected(host); +} + +void OptionsDialog::optionSelected(QListWidgetItem *current) +{ + int index = current->data(Qt::UserRole).toInt(); + ui->optionsStack->setCurrentIndex(index); +} + +void OptionsDialog::accept() +{ + m_httpProxyForm->apply(); + m_importPathsForm->apply(); + m_hostsForm->apply(); + QDialog::accept(); +} + +void OptionsDialog::reject() +{ + QDialog::reject(); +} + + diff --git a/src/bench/optionsdialog.h b/src/bench/optionsdialog.h new file mode 100644 index 0000000..c10eb49 --- /dev/null +++ b/src/bench/optionsdialog.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtGui> +#include <QtWidgets> + +namespace Ui { + class OptionsDialog; +} + +class HttpProxyOptionPage; +class ImportPathOptionPage; +class HostsOptionsPage; +class HostModel; +class Host; + +class OptionsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit OptionsDialog(QWidget *parent = 0); + ~OptionsDialog(); + + void setHostModel(HostModel* model); + void setDiscoveredHostsModel(HostModel* model); + + void openHostConfig(Host* host); + +private slots: + void optionSelected(QListWidgetItem* current); + void accept(); + void reject(); + +private: + Ui::OptionsDialog *ui; + HttpProxyOptionPage *m_httpProxyForm; + ImportPathOptionPage *m_importPathsForm; + HostsOptionsPage *m_hostsForm; +}; diff --git a/src/bench/optionsdialog.ui b/src/bench/optionsdialog.ui new file mode 100644 index 0000000..1ed4123 --- /dev/null +++ b/src/bench/optionsdialog.ui @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>OptionsDialog</class> + <widget class="QDialog" name="OptionsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>869</width> + <height>523</height> + </rect> + </property> + <property name="windowTitle"> + <string>Preferences</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QListWidget" name="optionsView"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="resizeMode"> + <enum>QListView::Adjust</enum> + </property> + <property name="selectionRectVisible"> + <bool>false</bool> + </property> + <property name="currentRow"> + <number>-1</number> + </property> + </widget> + <widget class="QStackedWidget" name="optionsStack"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>2</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>OptionsDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>OptionsDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/bench/previewimageprovider.cpp b/src/bench/previewimageprovider.cpp new file mode 100644 index 0000000..a020271 --- /dev/null +++ b/src/bench/previewimageprovider.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "previewimageprovider.h" +#include "contentadapterinterface.h" + +#include <QDebug> +#include <QFileIconProvider> +#include <QPainter> + + +class CacheImage { +public: + QImage image; + QDateTime time; +}; + +typedef QHash<QString, CacheImage> ImageHash; +typedef QHash<QString, QImage> QImageHash; + +Q_GLOBAL_STATIC(ImageHash, imageCache) +Q_GLOBAL_STATIC(QImageHash, iconCache) + +PreviewImageProvider::PreviewImageProvider(QObject *engine) + : QQuickImageProvider(QQuickImageProvider::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading) + , m_engine(engine) + , m_ignoreCache(false) +{ +} + +QImage PreviewImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) +{ + Q_ASSERT(size); + QFileInfo info(id); + info.refresh(); + QList<ContentAdapterInterface*> plugins; + QString hashKey = id + QString("%1x%2").arg(QString::number(requestedSize.width())).arg(QString::number(requestedSize.height())); + + { + QMutexLocker m(&m_mutex); + if (!m_ignoreCache && imageCache()->contains(hashKey)) { + CacheImage i = imageCache()->value(hashKey); + if (info.lastModified() <= i.time) { + *size = i.image.size(); + return i.image; + } + } + + plugins = m_plugins; + } + + foreach (ContentAdapterInterface* plugin, plugins) { + if (plugin->canPreview(id)) { + QImage img = plugin->preview(id, requestedSize); + *size = img.size(); + CacheImage i; + i.image = img; + i.time = info.lastModified(); + imageCache()->insert(hashKey, i); + + return img; + } + } + + + QImage img; + QString type = info.suffix(); + QSize iconSize = requestedSize; + if (!iconSize.isValid() || iconSize.isNull()) + iconSize = QSize(512, 512); + + if (iconCache()->contains(type)) { + img = iconCache()->value(type); + *size = img.size(); + } else if (m_engine){ + QMetaObject::invokeMethod(m_engine, "convertIconToImage", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QImage, img), + Q_ARG(QFileInfo, info), + Q_ARG(QSize, iconSize)); + iconCache()->insert(type, img); + *size = iconSize; + } + + return img; +} + +void PreviewImageProvider::setPlugins(QList<ContentAdapterInterface *> plugins) +{ + QMutexLocker m(&m_mutex); + m_plugins = plugins; +} + +void PreviewImageProvider::setIgnoreCache(bool enabled) +{ + QMutexLocker m(&m_mutex); + m_ignoreCache = enabled; +} + +bool PreviewImageProvider::ignoreCache() +{ + QMutexLocker m(&m_mutex); + return m_ignoreCache; +} diff --git a/src/bench/previewimageprovider.h b/src/bench/previewimageprovider.h new file mode 100644 index 0000000..2057e80 --- /dev/null +++ b/src/bench/previewimageprovider.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QQuickImageProvider> +#include <QMutex> +#include <QHash> +#include <QDateTime> + +class ContentAdapterInterface; +class PreviewImageProvider : public QObject, public QQuickImageProvider +{ + Q_OBJECT + +public: + explicit PreviewImageProvider(QObject *engine); + + QImage requestImage (const QString& id, QSize* size, const QSize& requestedSize); + + void setPlugins(QList<ContentAdapterInterface*> plugins); + void setIgnoreCache(bool enabled); + bool ignoreCache(); + +private: + + QList<ContentAdapterInterface*> m_plugins; + QMutex m_mutex; + QObject* m_engine; + bool m_ignoreCache; +}; diff --git a/src/bench/qmlpreviewadapter.cpp b/src/bench/qmlpreviewadapter.cpp new file mode 100644 index 0000000..d919989 --- /dev/null +++ b/src/bench/qmlpreviewadapter.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "qmlpreviewadapter.h" +#include <QFileInfo> +#include <QDir> +#include <QCoreApplication> +#include <QLocalSocket> +#include <QDebug> + +Q_GLOBAL_STATIC(QProcess, proc) +Q_GLOBAL_STATIC(QString, serverName) + + +QmlPreviewAdapter::QmlPreviewAdapter(QObject *parent) : + QObject(parent) +{ +} + +bool QmlPreviewAdapter::canPreview(const QString &path) const +{ + return path.endsWith(".qml"); +} + +QImage QmlPreviewAdapter::preview(const QString &path, const QSize &requestedSize) +{ + QImage img; + + if (!requestedSize.isValid()) { + qWarning() << "preview for" << path << "with invalid size" << requestedSize << "requested"; + return QImage(); + } + +#ifdef Q_OS_WINDOWS + static const QString suffix = ".exe"; +#else + static const QString suffix; +#endif + + static const QString program = QCoreApplication::applicationDirPath() + QDir::separator() + "previewGenerator" + suffix; + static const QStringList arguments("QmlLiveBench"); + + if (proc()->state() != QProcess::Running) { + QStringList env = QProcess::systemEnvironment(); + { + QMutexLocker m(&m_mutex); + env.append(QString("QT_PLUGIN_PATH=%1").arg(m_pluginPaths.join(":"))); + env.append(QString("QML_IMPORT_PATH=%1").arg(m_importPaths.join(":"))); + env.append(QString("QML2_IMPORT_PATH=%1").arg(m_importPaths.join(":"))); + } + proc()->setEnvironment(env); + proc()->start(program, arguments); + if (!proc()->waitForStarted()) { + qWarning() << "Failed to start" << program; + return QImage(); + } + + proc()->waitForReadyRead(); + QByteArray data = proc()->readAll(); + if (!data.startsWith("ready#")) { + qWarning() << "previewGenerator did not send the \"ready\" token:" << proc()->readAllStandardError(); + return QImage(); + } + QString server = QString::fromUtf8(QByteArray::fromHex(data.mid(6))); + *serverName() = server; + } + + QLocalSocket socket; + + socket.connectToServer(*serverName()); + if (!socket.waitForConnected(3000)) { + qWarning() << "Could not connect to PreviewGenerator"; + return QImage(); + } + + //qWarning() << "QL: sending request [" << requestedSize << "]" << path; + + { + QDataStream ds(&socket); + ds << requestedSize << path; + } + socket.waitForBytesWritten(); + + //qWarning() << "QL: sent"; + + QByteArray data; + bool allData = false; + while (!allData) { + int bytes = socket.bytesAvailable(); + //qWarning() << "QL: can read" << bytes << "bytes"; + + if (proc()->state() != QProcess::Running) { + qWarning() << "previewGenerator stopped unexpectedly"; + break; + } + + if (!bytes) { + //qWarning() << "QL: waiting for more data (have" << data.size() << "already)"; + socket.waitForReadyRead(5000); + continue; + } + + data += socket.read(bytes); + + if (data.endsWith("\nEND")) { + allData = true; + data.chop(4); + //qWarning() << "QL: received end marker after" << data.size() << "bytes"; + } + } + socket.close(); + + img.loadFromData(data, "PNG"); + + if (img.size().isNull()) { + qWarning() << "Failed to generate Preview:" << proc()->readAllStandardError(); + + img = QImage("://livert/no.png"); + } + + return img; +} + +bool QmlPreviewAdapter::canAdapt(const QUrl &url) const +{ + Q_UNUSED(url); + + return false; +} + +QUrl QmlPreviewAdapter::adapt(const QUrl &url, QQmlContext *context) +{ + Q_UNUSED(url); + Q_UNUSED(context); + + return QUrl(); +} + +void QmlPreviewAdapter::setImportPaths(QStringList importPaths) +{ + QMutexLocker m(&m_mutex); + m_importPaths = importPaths; +} + +void QmlPreviewAdapter::setPluginPaths(QStringList pluginPaths) +{ + QMutexLocker m(&m_mutex); + m_importPaths = pluginPaths; +} diff --git a/src/bench/qmlpreviewadapter.h b/src/bench/qmlpreviewadapter.h new file mode 100644 index 0000000..2dba44b --- /dev/null +++ b/src/bench/qmlpreviewadapter.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include "contentadapterinterface.h" +#include <QMutex> +#include <QStringList> +#include <QProcess> + +class QmlContext; +class QDeclarativeContext; +class QmlPreviewAdapter : public QObject, public ContentAdapterInterface +{ + Q_OBJECT + Q_INTERFACES(ContentAdapterInterface) +public: + explicit QmlPreviewAdapter(QObject *parent = 0); + + bool canPreview(const QString& path) const; + QImage preview(const QString& path, const QSize &requestedSize); + + bool canAdapt(const QUrl& url) const; + virtual QUrl adapt(const QUrl& url, QQmlContext* context); + + void setImportPaths(QStringList importPaths); + void setPluginPaths(QStringList pluginPaths); + +private: + + QStringList m_pluginPaths; + QStringList m_importPaths; + QMutex m_mutex; +}; diff --git a/src/bench/reload.pro b/src/bench/reload.pro new file mode 100644 index 0000000..89a9668 --- /dev/null +++ b/src/bench/reload.pro @@ -0,0 +1,33 @@ +TEMPLATE = app +TARGET = livereload + +equals(QT_MAJOR_VERSION, "5"): CONFIG += qt5 + +QT = gui core +qt5:QT += quick widgets core-private +else:QT += declarative + +osx: CONFIG -= app_bundle + +qt5:DEFINES += USING_QT5 +else:DEFINES += USING_QT4 + +SOURCES += \ + main.cpp \ + watcher.cpp \ + mainwindow.cpp + +qt5:SOURCES += windowwidget.cpp + +HEADERS += \ + watcher.h \ + mainwindow.h + +qt5:HEADERS += windowwidget.h + +RESOURCES += \ + reload.qrc + +OTHER_FILES += \ + error.qml \ + error2.qml diff --git a/src/bench/reload.qrc b/src/bench/reload.qrc new file mode 100644 index 0000000..2c37c6e --- /dev/null +++ b/src/bench/reload.qrc @@ -0,0 +1,8 @@ +<RCC> + <qresource prefix="/"> + <file>logo.png</file> + <file>error.qml</file> + <file>error2.qml</file> + <file>livert/ImageViewer.qml</file> + </qresource> +</RCC> diff --git a/src/concept.dox b/src/concept.dox new file mode 100644 index 0000000..e7cabed --- /dev/null +++ b/src/concept.dox @@ -0,0 +1,10 @@ +/*! + \page concept Concept + + \tableofcontents + + \section Fundamentals + + QmlLive provides a way to synchronize a workspace on the same machine or across devices and manage the active shown document. + +*/ diff --git a/src/contentadapterinterface.h b/src/contentadapterinterface.h new file mode 100644 index 0000000..c589eef --- /dev/null +++ b/src/contentadapterinterface.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QObject> +#include <QUrl> +#include <QImage> + +class QDeclarativeContext; +class QQmlContext; +//! [0] +class ContentAdapterInterface +{ +public: + + enum Feature { + QtQuickControls = 0x1 + }; + Q_DECLARE_FLAGS(Features, Feature) + + virtual ~ContentAdapterInterface() {} + + virtual void cleanUp() {} + + virtual bool canPreview(const QString& path) const = 0; + virtual QImage preview(const QString& path, const QSize &requestedSize) = 0; + + virtual bool canAdapt(const QUrl& url) const = 0; + virtual bool isFullScreen() const { return false; } + + void setAvailableFeatures(ContentAdapterInterface::Features features) { m_features = features; } + ContentAdapterInterface::Features availableFeatures() { return m_features; } + + virtual QUrl adapt(const QUrl& url, QQmlContext* context) = 0; + +private: + Features m_features; +}; +//! [0] + +Q_DECLARE_OPERATORS_FOR_FLAGS(ContentAdapterInterface::Features) +Q_DECLARE_INTERFACE(ContentAdapterInterface, "com.pelagicore.qmllive.ContentAdapterInterface/1.0") + diff --git a/src/contentpluginfactory.cpp b/src/contentpluginfactory.cpp new file mode 100644 index 0000000..1894ab3 --- /dev/null +++ b/src/contentpluginfactory.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "contentpluginfactory.h" +#include "contentadapterinterface.h" + +#include <QPluginLoader> +#include <QDirIterator> +#include <QDebug> + +ContentPluginFactory::ContentPluginFactory(QObject *parent) : + QObject(parent) , + m_loaded(false) +{ + m_pluginPath = QDir::currentPath() + QDir::separator() + "plugins"; +} + +void ContentPluginFactory::setPluginPath(const QString &path) +{ + m_pluginPath = path; +} + +QString ContentPluginFactory::pluginPath() +{ + return m_pluginPath; +} + + +QList<ContentAdapterInterface *> ContentPluginFactory::plugins() +{ + return m_plugins; +} + +bool ContentPluginFactory::isLoaded() +{ + return m_loaded; +} + +void ContentPluginFactory::load() +{ + if (m_loaded) + return; + + QDirIterator it(m_pluginPath); + + while (it.hasNext()) { + const QString path = it.next(); + + if (!it.fileInfo().isFile()) + continue; + + QPluginLoader loader(path); + + ContentAdapterInterface* plugin = qobject_cast<ContentAdapterInterface*>(loader.instance()); + if (plugin) + m_plugins.append(plugin); + + if (!loader.isLoaded()) + qWarning() << "Error while trying to load" <<path << ":" << loader.errorString(); + } + + if (!m_plugins.isEmpty()) + m_loaded = true; +} diff --git a/src/contentpluginfactory.h b/src/contentpluginfactory.h new file mode 100644 index 0000000..29e83b4 --- /dev/null +++ b/src/contentpluginfactory.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QObject> + +class ContentAdapterInterface; +class ContentPluginFactory : public QObject +{ + Q_OBJECT +public: + explicit ContentPluginFactory(QObject *parent = 0); + + void setPluginPath(const QString& path); + QString pluginPath(); + + QList<ContentAdapterInterface*> plugins(); + bool isLoaded(); + +public Q_SLOTS: + + void load(); + +private: + QString m_pluginPath; + QList<ContentAdapterInterface*> m_plugins; + bool m_loaded; +}; diff --git a/src/fontadapter.cpp b/src/fontadapter.cpp new file mode 100644 index 0000000..6825a54 --- /dev/null +++ b/src/fontadapter.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "fontadapter.h" +#include <QDebug> +#include <QQmlContext> + +FontAdapter::FontAdapter(QObject *parent) : + QObject(parent), + fontId(-1) +{ + fontExtensions.append(".ttf"); + fontExtensions.append(".otf"); +} + +void FontAdapter::cleanUp() +{ + base.removeAllApplicationFonts(); +} + +bool FontAdapter::canPreview(const QString &path) const +{ + Q_UNUSED(path); + + return false; +} + +QImage FontAdapter::preview(const QString &path, const QSize &requestedSize) +{ + Q_UNUSED(path); + Q_UNUSED(requestedSize); + + return QImage(); +} + +bool FontAdapter::canAdapt(const QUrl &url) const +{ + QString path = url.toLocalFile(); + + foreach (const QString& extension, fontExtensions) { + if (path.endsWith(extension)) + return true; + } + + return false; +} + +bool FontAdapter::isFullScreen() const +{ + return true; +} + +QUrl FontAdapter::adapt(const QUrl &url, QQmlContext *context) +{ + fontId = base.addApplicationFont(url.toLocalFile()); + + QStringList families = base.applicationFontFamilies(fontId); + + QVariantList styles; + foreach (QString family, families) { + QVariantMap style; + QVariantList weights; + foreach (QString styleName, base.styles(family)) { + QVariantMap newWeight; + int styleWeight = base.weight(family, styleName); + + newWeight.insert("name", styleName); + newWeight.insert("weight", styleWeight); + + bool added = false; + for (int i=0; i < weights.count(); i++) { + if (styleWeight <= weights.at(i).toMap().value("weight").toInt()) { + added = true; + weights.insert(i, newWeight); + break; + } + } + + if (!added) + weights.append(newWeight); + } + + style.insert("family", family); + style.insert("weights", weights); + styles.append(style); + } + + context->setContextProperty("styles", styles); + + if (availableFeatures().testFlag(QtQuickControls)) + return QUrl("qrc:/livert/fontviewer_qt5_controls.qml"); + + return QUrl("qrc:/livert/fontviewer_qt5.qml"); +} diff --git a/src/fontadapter.h b/src/fontadapter.h new file mode 100644 index 0000000..9eb2152 --- /dev/null +++ b/src/fontadapter.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include "contentadapterinterface.h" +#include <QStringList> +#include <QFontDatabase> + +class QDeclarativeContext; +class FontAdapter : public QObject, public ContentAdapterInterface +{ + Q_OBJECT + Q_INTERFACES(ContentAdapterInterface) +public: + explicit FontAdapter(QObject *parent = 0); + + void cleanUp(); + + bool canPreview(const QString& path) const; + QImage preview(const QString& path, const QSize &requestedSize); + + bool canAdapt(const QUrl& url) const; + + bool isFullScreen() const; + + virtual QUrl adapt(const QUrl& url, QQmlContext* context); + +private: + QStringList fontExtensions; + QFontDatabase base; + int fontId; +}; diff --git a/src/imageadapter.cpp b/src/imageadapter.cpp new file mode 100644 index 0000000..439ab8b --- /dev/null +++ b/src/imageadapter.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "imageadapter.h" +#include <QImageReader> +#include <QDebug> +#include <QFileInfo> +#include <QQmlContext> + +ImageAdapter::ImageAdapter(QObject *parent) : + QObject(parent) +{ +} + +bool ImageAdapter::canPreview(const QString &path) const +{ + QString format = QImageReader::imageFormat(path); + if (!format.isEmpty()) { + if (format == "pcx") { + if (QFileInfo(path).suffix() == "pcx") + return true; + } else { + return true; + } + } + + return false; +} + +QImage ImageAdapter::preview(const QString &path, const QSize &requestedSize) +{ + QImage img(path); + + if (requestedSize.isValid()) + return img.scaled(requestedSize, Qt::KeepAspectRatio); + return img; +} + +bool ImageAdapter::canAdapt(const QUrl &url) const +{ + return !QImageReader::imageFormat(url.toLocalFile()).isEmpty(); +} + +QUrl ImageAdapter::adapt(const QUrl &url, QQmlContext *context) +{ + context->setContextProperty("imageViewerBackgroundColor", "black"); + context->setContextProperty("imageViewerSource", url); + + return QUrl("qrc:/livert/imageviewer_qt5.qml"); +} diff --git a/src/imageadapter.h b/src/imageadapter.h new file mode 100644 index 0000000..3d64f57 --- /dev/null +++ b/src/imageadapter.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include "contentadapterinterface.h" + +class QDeclarativeContext; +class ImageAdapter : public QObject, public ContentAdapterInterface +{ + Q_OBJECT + Q_INTERFACES(ContentAdapterInterface) +public: + explicit ImageAdapter(QObject *parent = 0); + + bool canPreview(const QString& path) const; + QImage preview(const QString& path, const QSize &requestedSize); + + bool canAdapt(const QUrl& url) const; + + virtual QUrl adapt(const QUrl& url, QQmlContext* context); +}; + diff --git a/src/images/client.png b/src/images/client.png Binary files differnew file mode 100644 index 0000000..1192b0f --- /dev/null +++ b/src/images/client.png diff --git a/src/images/concept.png b/src/images/concept.png Binary files differnew file mode 100644 index 0000000..dec994d --- /dev/null +++ b/src/images/concept.png diff --git a/src/images/creator_result.png b/src/images/creator_result.png Binary files differnew file mode 100644 index 0000000..a26a980 --- /dev/null +++ b/src/images/creator_result.png diff --git a/src/images/creator_shortcut.png b/src/images/creator_shortcut.png Binary files differnew file mode 100644 index 0000000..18d8106 --- /dev/null +++ b/src/images/creator_shortcut.png diff --git a/src/images/creator_tool.png b/src/images/creator_tool.png Binary files differnew file mode 100644 index 0000000..a34b403 --- /dev/null +++ b/src/images/creator_tool.png diff --git a/src/images/favicon.png b/src/images/favicon.png Binary files differnew file mode 100644 index 0000000..4714c88 --- /dev/null +++ b/src/images/favicon.png diff --git a/src/images/graphics_sheets.png b/src/images/graphics_sheets.png Binary files differnew file mode 100644 index 0000000..d9c9f5a --- /dev/null +++ b/src/images/graphics_sheets.png diff --git a/src/images/icon_failover.png b/src/images/icon_failover.png Binary files differnew file mode 100644 index 0000000..1ce4c0f --- /dev/null +++ b/src/images/icon_failover.png diff --git a/src/images/icon_offline.png b/src/images/icon_offline.png Binary files differnew file mode 100644 index 0000000..760524e --- /dev/null +++ b/src/images/icon_offline.png diff --git a/src/images/icon_online.png b/src/images/icon_online.png Binary files differnew file mode 100644 index 0000000..62f64d9 --- /dev/null +++ b/src/images/icon_online.png diff --git a/src/images/qml_sheets.png b/src/images/qml_sheets.png Binary files differnew file mode 100644 index 0000000..9037f00 --- /dev/null +++ b/src/images/qml_sheets.png diff --git a/src/images/remote.png b/src/images/remote.png Binary files differnew file mode 100644 index 0000000..0d7872f --- /dev/null +++ b/src/images/remote.png diff --git a/src/images/runtime.png b/src/images/runtime.png Binary files differnew file mode 100644 index 0000000..41804af --- /dev/null +++ b/src/images/runtime.png diff --git a/src/images/server.png b/src/images/server.png Binary files differnew file mode 100644 index 0000000..5e00a21 --- /dev/null +++ b/src/images/server.png diff --git a/src/images/workbench.png b/src/images/workbench.png Binary files differnew file mode 100644 index 0000000..9c4ec78 --- /dev/null +++ b/src/images/workbench.png diff --git a/src/ipc/ipc.dox b/src/ipc/ipc.dox new file mode 100644 index 0000000..6b4eeb2 --- /dev/null +++ b/src/ipc/ipc.dox @@ -0,0 +1,14 @@ +/*! + \defgroup ipc Ipc Communication + + A set of classes to support ipc client and server. +*/ + +/*! + @{ +*/ + +/*! + @} +*/ + diff --git a/src/ipc/ipc.pri b/src/ipc/ipc.pri new file mode 100644 index 0000000..85ae7e9 --- /dev/null +++ b/src/ipc/ipc.pri @@ -0,0 +1,11 @@ +QT += network + +SOURCES += \ + $$PWD/ipcserver.cpp \ + $$PWD/ipcconnection.cpp \ + $$PWD/ipcclient.cpp + +HEADERS += \ + $$PWD/ipcserver.h \ + $$PWD/ipcconnection.h \ + $$PWD/ipcclient.h diff --git a/src/ipc/ipcclient.cpp b/src/ipc/ipcclient.cpp new file mode 100644 index 0000000..e3a0846 --- /dev/null +++ b/src/ipc/ipcclient.cpp @@ -0,0 +1,384 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "ipcclient.h" +#include <QElapsedTimer> +#include <QPointer> + +#ifdef QMLLIVE_IPC_DEBUG +#define DEBUG qDebug() +#else +#define DEBUG if (0) qDebug() +#endif + +class Package : public QObject { +public: + QUuid m_uuid; + QString m_method; + QByteArray m_data; + int m_tries; + qint64 m_bytes; +}; + +/*! + * \class IpcClient + * \brief Client to send remote calls to an IpcServer + * \group ipc + * + * The IPC system uses the normalized signal/slot signature to + * identify a message call. The arguments are passed as a QByteArray to the + * send function. + * + * Here is a simple example: + * \code{.cpp} + * IpcClient *client = new IpcClient(this); + * client->connectToServer("127.0.0.1", 10234); + * QString text = "Hello"; + * QByteArray content; + * QDataStream out(&bytes, QIODevice::WriteOnly); + * out << text; + * QUuid uuid = client->send("echo(QString)", content); + * client->waitForSent(uuid); + * \endcode + * + * Don't use the waitFor*-Methods in your gui applications. They will block + * the eventloop. Instead react on the signals when the packages are sent or + * an error happened. + */ + +/*! + * \brief Constructs an IpcClient with parent \a parent to send commands to an IpcServer. + */ +IpcClient::IpcClient(QObject *parent) + : QObject(parent) + , m_socket(new QTcpSocket(this)) + , m_current(0) + , m_written(0) + , m_connection(new IpcConnection(m_socket)) +{ + connect(m_socket, SIGNAL(connected()), this, SIGNAL(connected())); + connect(m_socket, SIGNAL(connected()), this, SLOT(processQueue())); + connect(m_socket, SIGNAL(disconnected()), this, SIGNAL(disconnected())); + connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError))); + connect(m_socket, SIGNAL(bytesWritten(qint64)), this , SLOT(onBytesWritten(qint64))); + + connect(m_connection, SIGNAL(received(QString,QByteArray)), this, SIGNAL(received(QString,QByteArray))); +} + +IpcClient::IpcClient(QTcpSocket *socket, QObject *parent) + : QObject(parent) + , m_socket(socket) + , m_current(0) + , m_written(0) + , m_connection(0) +{ + connect(m_socket, SIGNAL(connected()), this, SIGNAL(connected())); + connect(m_socket, SIGNAL(disconnected()), this, SIGNAL(disconnected())); + connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError))); + connect(m_socket, SIGNAL(bytesWritten(qint64)), this , SLOT(onBytesWritten(qint64))); +} + +QAbstractSocket::SocketState IpcClient::state() const +{ + return m_socket->state(); +} + +/*! + * Sets the Ip-Address to \a hostName and port to \a port to be used for a ipc call. + */ +void IpcClient::connectToServer(const QString &hostName, int port) +{ + m_socket->connectToHost(hostName, port); +} + +/*! + * Send call to server given by destination + * + * Expects the \a method to be in the form of "echo(QString)" and uses \a data as the content of the arguments + * Returns a QUuid which identifies this Package + * + * \sa sentSuccessfully(), sendingError() + */ +QUuid IpcClient::send(const QString &method, const QByteArray &data) +{ + Package* pkg = new Package; + pkg->m_method = method; + pkg->m_data = data; + pkg->m_uuid = QUuid::createUuid(); + pkg->m_bytes = 0; + pkg->m_tries = 0; + m_queue.enqueue(pkg); + + QTimer::singleShot(0, this, SLOT(processQueue())); + + return pkg->m_uuid; +} + +/*! + * Waits until the client is connected to the server + * \a msecs specfies the time how long to wait + * Returns true when the client is connected + * + * This call blocks your eventloop() + * + * \sa waitForDisconnected(), waitForSent() + */ +bool IpcClient::waitForConnected(int msecs) +{ + return m_socket->waitForConnected(msecs); +} + +/*! + * Waits until the client is disconnected from the server + * \a msecs specfies the time how long to wait + * Returns true when the client is disconnected + * + * This call blocks your eventloop() + * + * \sa waitForConnected(), waitForSent() + */ +bool IpcClient::waitForDisconnected(int msecs) +{ + return m_socket->waitForDisconnected(msecs); +} + +/*! + * Waits until the Package identified by \a uuid is sent + * \arg msecs specfies the time how long to wait + * Returns true when the Package is sent successfully + * + * This call blocks your eventloop() + * + * \sa waitForConnected(), waitForDisconnected() + */ +bool IpcClient::waitForSent(const QUuid uuid, int msecs) +{ + QPointer<Package> waitForPackage = 0; + if (m_current && m_current->m_uuid == uuid) { + waitForPackage = m_current; + } else { + foreach (Package* pkg, m_queue) { + if (pkg->m_uuid == uuid) { + waitForPackage = pkg; + break; + } + } + } + + if (!waitForPackage) + return false; + + QElapsedTimer stopWatch; + stopWatch.start(); + + bool sent = false; + while (!sent && (msecs == -1 || stopWatch.elapsed() < msecs)) { + if (!m_socket->waitForBytesWritten(msecs - stopWatch.elapsed())) + return false; + + if (!waitForPackage) + return m_lastSuccess == uuid; + } + + return false; +} + +QString IpcClient::errorToString(QAbstractSocket::SocketError error) +{ + switch (error) { + + case QAbstractSocket::ConnectionRefusedError: + return QString("The connection was refused by the peer (or timed out)."); + case QAbstractSocket::RemoteHostClosedError: + return QString("The remote host closed the connection."); + case QAbstractSocket::HostNotFoundError: + return QString("The host address was not found."); + case QAbstractSocket::SocketAccessError: + return QString("You don't have the required privileges."); + case QAbstractSocket::SocketResourceError: + return QString("The local system ran out of resources (e.g., too many sockets)."); + case QAbstractSocket::SocketTimeoutError: + return QString("The socket operation timed out."); + case QAbstractSocket::DatagramTooLargeError: + return QString("The datagram was larger than the operating system's limit (which can be as low as 8192 bytes)."); + case QAbstractSocket::NetworkError: + return QString("An error occurred with the network (e.g., the network cable was accidentally plugged out)."); + case QAbstractSocket::AddressInUseError: + return QString("Address already in use."); + case QAbstractSocket::SocketAddressNotAvailableError: + return QString("Address not available."); + case QAbstractSocket::UnsupportedSocketOperationError: + return QString("Unsupported Socket."); + case QAbstractSocket::ProxyAuthenticationRequiredError: + return QString("The socket is using a proxy, and the proxy requires authentication."); + case QAbstractSocket::SslHandshakeFailedError: + return QString("The SSL/TLS handshake failed, so the connection was closed"); + case QAbstractSocket::UnfinishedSocketOperationError: + return QString("The last operation attempted has not finished yet (still in progress in the background)."); + case QAbstractSocket::ProxyConnectionRefusedError: + return QString("Could not contact the proxy server because the connection to that server was denied."); + case QAbstractSocket::ProxyConnectionClosedError: + return QString("The connection to the proxy server was closed unexpectedly (before the connection to the final peer was established)."); + case QAbstractSocket::ProxyConnectionTimeoutError: + return QString("The connection to the proxy server timed out or the proxy server stopped responding in the authentication phase."); + case QAbstractSocket::ProxyNotFoundError: + return QString("The proxy address was not found."); + case QAbstractSocket::ProxyProtocolError: + return QString("The connection negotiation with the proxy server because the response from the proxy server could not be understood."); + case QAbstractSocket::UnknownSocketError: + return QString("Unknown Error"); + case QAbstractSocket::OperationError: + return QString("An operation was attempted while the socket was in a state that did not permit it."); + case QAbstractSocket::SslInternalError: + return QString("The SSL library being used reported a internal error, this is probably the result of a bad installation or misconfiguration of the library."); + case QAbstractSocket::SslInvalidUserDataError: + return QString("Invalid data(certificate, key, cypher, etc.) was provided and its use resulted in an error in the SSL library."); + case QAbstractSocket::TemporaryError: + return QString("A temporary error occurred(e.g., operation would block and socket is non-blocking)."); + } + + return QString("No Error Description for this Error"); +} + +/*! + * Disconnects from the Server + */ +void IpcClient::disconnectFromServer() +{ + m_socket->disconnectFromHost(); +} + +void IpcClient::processQueue() +{ + if (m_current) + return; + + if (!m_queue.isEmpty()) { + m_current = m_queue.head(); + m_current->m_tries++; + + if (m_current->m_tries >= 5) { + DEBUG << "Tried to sent the package" << m_current->m_tries << "times, but didn't succeed"; + m_queue.dequeue(); + onError(QAbstractSocket::ConnectionRefusedError); + QTimer::singleShot(0, this, SLOT(processQueue())); + return; + } + + int size = sendPackage(m_current->m_method, m_current->m_data); + + if (size != -1) { + m_queue.dequeue(); + m_current->m_bytes = size; + } else { + QTimer::singleShot(1000, this, SLOT(processQueue())); + m_current = 0; + } + } +} + +void IpcClient::onBytesWritten(qint64 written) +{ + Q_ASSERT(m_current); + + m_written += written; + if (m_written < m_current->m_bytes) + return; + + m_written = m_written - m_current->m_bytes; + emit sentSuccessfully(m_current->m_uuid); + m_lastSuccess = m_current->m_uuid; + delete m_current; + m_current = 0; + + processQueue(); +} + +void IpcClient::onError(QAbstractSocket::SocketError socketError) +{ + if (m_current) { + emit sendingError(m_current->m_uuid, socketError); + delete m_current; + m_current = 0; + + QTimer::singleShot(0, this, SLOT(processQueue())); + } + + if ((m_socket->state() != QAbstractSocket::ConnectedState && + m_socket->state() != QAbstractSocket::BoundState) || + socketError == QAbstractSocket::RemoteHostClosedError) { + emit connectionError(socketError); + } +} + +qint64 IpcClient::sendPackage(const QString &method, const QByteArray &data) +{ + DEBUG << "IpcClient::send: " << method; + + if (!m_socket->isValid() || m_socket->state() != QAbstractSocket::ConnectedState) { + DEBUG << "Tried to write on a Unconnected Socket. Try again later"; + return -1; + } + + m_socket->write(QString("Method:%1\n").arg(method).toLatin1()); + m_socket->write(QString("Content-Length:%1\n").arg(data.length()).toLatin1()); + m_socket->write(QString("\n").toLatin1()); + m_socket->write(data); + + return m_socket->bytesToWrite(); +} + +/*! + * \fn void IpcClient::connected(); + * Emitted once when the connection to the server is established + */ + +/*! + * \fn void IpcClient::disconnected(); + * Emitted once when the connection to the server is terminated + */ + +/*! + * \fn void IpcClient::connectionError(QAbstractSocket::SocketError socketError); + * Emitted when an error happens when connecting or disconnecting from the server + * \a socketError describes what error happened + */ + +/*! + * \fn void IpcClient::sentSuccessfully(const QUuid& uuid); + * Emitted when the Package identified by \a uuid was successfully sent. + */ + +/*! + * \fn void IpcClient::sendingError(const QUuid& uuid, QAbstractSocket::SocketError socketError); + * Emitted when an error happens when sending the Package identified by \a uuid. + * \a socketError describes what error happened + */ + diff --git a/src/ipc/ipcclient.h b/src/ipc/ipcclient.h new file mode 100644 index 0000000..dd9190f --- /dev/null +++ b/src/ipc/ipcclient.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QTcpSocket> +#include <QUuid> +#include <QQueue> +#include "ipcconnection.h" + +class Package; +class IpcClient : public QObject +{ + Q_OBJECT +public: + explicit IpcClient(QObject *parent = 0); + IpcClient(QTcpSocket* socket, QObject *parent = 0); + + QAbstractSocket::SocketState state() const; + + void connectToServer(const QString& hostName, int port); + QUuid send(const QString& method, const QByteArray& data); + + bool waitForConnected(int msecs = 30000); + bool waitForDisconnected(int msecs = 30000); + bool waitForSent(const QUuid uuid, int msecs = 30000); + + QString errorToString(QAbstractSocket::SocketError error); + +Q_SIGNALS: + void connected(); + void disconnected(); + void connectionError(QAbstractSocket::SocketError socketError); + + void sentSuccessfully(const QUuid& uuid); + void sendingError(const QUuid& uuid, QAbstractSocket::SocketError socketError); + + void received(const QString& method, const QByteArray& content); + +public Q_SLOTS: + void disconnectFromServer(); + +private Q_SLOTS: + void processQueue(); + void onBytesWritten(qint64 written); + void onError(QAbstractSocket::SocketError socketError); + +private: + qint64 sendPackage(const QString& method, const QByteArray& data); + + QTcpSocket *m_socket; + QQueue<Package*> m_queue; + Package* m_current; + qint64 m_written; + QUuid m_lastSuccess; + + IpcConnection* m_connection; +}; + diff --git a/src/ipc/ipcconnection.cpp b/src/ipc/ipcconnection.cpp new file mode 100644 index 0000000..7b9c4d9 --- /dev/null +++ b/src/ipc/ipcconnection.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "ipcconnection.h" + +#ifdef QMLLIVE_IPC_DEBUG +#define DEBUG qDebug() +#else +#define DEBUG if (0) qDebug() +#endif + +/** + * \class IpcConnection + * \brief Handles a single connection from the IpcServer + * \group ipc + */ + +/** + * \brief Constructs a IpcConnection with \a socket and a \a parent + */ +IpcConnection::IpcConnection(QTcpSocket *socket, QObject *parent) + : QObject(parent) + , m_socket(socket) + , m_headerComplete(false) + , m_maxContentSize(1024*1024*10) +{ + DEBUG << "IpcConnection()"; + + connect(m_socket, SIGNAL(disconnected()), this, SLOT(close())); + connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(closeWithError())); + connect(m_socket, SIGNAL(readyRead()), this, SLOT(readData())); +} + +/** + * \brief Close the connection and delete it + */ +void IpcConnection::close() +{ + DEBUG << "IpcConnection::close()"; + emit connectionClosed(); +} + +/** + * \brief Report errors and close the connection + */ +void IpcConnection::closeWithError() +{ + DEBUG << "IpcConnection::closeWithError: " << m_socket->errorString(); + emit error(m_socket->errorString()); + close(); +} + +/** + * \brief handles incoming data + */ +void IpcConnection::readData() +{ + while (m_socket->bytesAvailable()) { + if (!m_headerComplete) { + + //Not enough bytesAvailable() try again later. + if (!m_socket->canReadLine()) + return; + + while (m_socket->canReadLine()) { + QString line = m_socket->readLine().trimmed(); + DEBUG << "\treceived header: " << line; + if (line.isEmpty()) { + DEBUG << "\theader complete"; + if (m_headers.contains("Method") || m_headers.contains("Content-Length")) { + m_headerComplete = true; + } else { // we can't recover + qWarning() << "\tincomplete header"; + reset(); + } + break; + } + QStringList parts = line.split(":"); + if (parts.count() != 2) { + qWarning() << "invalid header line: " << line; + break; + } + m_headers.insert(parts.at(0).trimmed(), parts.at(1).trimmed()); + } + } + if (m_headerComplete) { + int bufferSize = m_headers.value("Content-Length").toInt(); + if (bufferSize > m_maxContentSize) { + qWarning() << "content to large to be received. max size: " << m_maxContentSize; + reset(); + return; + } + + DEBUG << "receive content (bytes): " << bufferSize; + if (m_socket->bytesAvailable() < bufferSize) { + DEBUG << "content wait for more data"; + return; + } else { + QByteArray content; + content.resize(bufferSize); + if (m_socket->read(content.data(), bufferSize) != bufferSize) { + qWarning() << "error reading content from stream"; + } + QString method = m_headers.value("Method"); + reset(); + emit received(method, content); + } + } + } +} + +/** + * \brief Max bytes we are able to receive. Defaults to 10Mbytes. + * Returns the max content size + */ +qint64 IpcConnection::maxContentSize() const +{ + return m_maxContentSize; +} + +void IpcConnection::reset() +{ + m_headerComplete = false; + m_headers.clear(); +} + +QTcpSocket *IpcConnection::socket() const +{ + return m_socket; +} diff --git a/src/ipc/ipcconnection.h b/src/ipc/ipcconnection.h new file mode 100644 index 0000000..821342a --- /dev/null +++ b/src/ipc/ipcconnection.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> +#include <QtNetwork> + +class IpcConnection : public QObject +{ + Q_OBJECT +public: + explicit IpcConnection(QTcpSocket* socket, QObject *parent = 0); + QTcpSocket* socket() const; +private: + void setMaxContentSize(qint64 size); + qint64 maxContentSize() const; + void reset(); +private Q_SLOTS: + void close(); + void closeWithError(); + void readData(); +Q_SIGNALS: + void connectionClosed(); + void error(const QString& message); + void received(const QString& method, const QByteArray& content); +private: + QTcpSocket *m_socket; + QHash<QString,QString> m_headers; + bool m_headerComplete; + qint64 m_maxContentSize; +}; + diff --git a/src/ipc/ipcserver.cpp b/src/ipc/ipcserver.cpp new file mode 100644 index 0000000..623cbff --- /dev/null +++ b/src/ipc/ipcserver.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "ipcserver.h" +#include "ipcconnection.h" + +#ifdef QMLLIVE_IPC_DEBUG +#define DEBUG qDebug() +#else +#define DEBUG if (0) qDebug() +#endif + +/*! + * \class IpcServer + * \brief The IpcServer listens on a port and creates an IpcConnection for an incoming + * connection. + * \group ipc + * + * The IPC server receives a method call from the client an notifies the user through + * the IpcServer::received signal. + * + * \code{.cpp} + * m_server = new IpcServer(this); + * connect( + * m_server, SIGNAL(received(QString,QByteArray)), + * this, SLOT(handleCall(QString, QByteArray)) + * ); + * m_server->listen(10234); + * + * ... + * + * MyHandler::handleCall(const QString& method, const QByteArray& contnt) { + * if (method == "echo(QString)") { + * QString text; + * QDataStream in(content); + * in >> text; + * qDebug() << "call received: " << method << ": " << text; + * } + * } + * \endcode + */ + +/*! + * \brief Standard constructor using \a parent as parent object + */ +IpcServer::IpcServer(QObject *parent) + : QObject(parent) + , m_server(new QTcpServer(this)) +{ + connect(m_server, SIGNAL(newConnection()), this, SLOT(newConnection())); +} + +/*! + * \brief listens to incomong connections on \a port + */ +void IpcServer::listen(int port) +{ + DEBUG << "IpcServer::listen: " << port; + m_server->listen(QHostAddress::Any, port); +} + +/*! + * \brief Creates a IpcConnection on incoming connection + */ +void IpcServer::newConnection() +{ + DEBUG << "IpcServer::newConnection"; + if (m_server->hasPendingConnections()) { + QTcpSocket* socket = m_server->nextPendingConnection(); + emit clientConnected(socket->peerAddress()); + emit clientConnected(socket); + IpcConnection* connection = new IpcConnection(socket, this); + connect(connection, SIGNAL(connectionClosed()), this, SLOT(onConnectionClosed())); + connect(connection, SIGNAL(received(QString,QByteArray)), this, SIGNAL(received(QString,QByteArray))); + } +} + +/*! + * \fn void IpcServer::received(const QString& method, const QByteArray& content); + * \brief signals a ipc call has arrived + * + * A ipc call requesting \a method and using \a content a the parameters for the method + */ + + +void IpcServer::onConnectionClosed() +{ + IpcConnection* connection = qobject_cast<IpcConnection*>(sender()); + + emit clientDisconnected(connection->socket()->peerAddress()); + emit clientDisconnected(connection->socket()); + + if (connection->parent() == this) + delete connection; +} + +void IpcServer::setMaxConnections(int num) +{ + m_server->setMaxPendingConnections(num); +} diff --git a/src/ipc/ipcserver.h b/src/ipc/ipcserver.h new file mode 100644 index 0000000..337ea3d --- /dev/null +++ b/src/ipc/ipcserver.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> +#include <QtNetwork> + +class IpcServer : public QObject +{ + Q_OBJECT +public: + explicit IpcServer(QObject *parent = 0); + void listen(int port); + void setMaxConnections(int num); +private Q_SLOTS: + void newConnection(); +Q_SIGNALS: + void received(const QString& method, const QByteArray& content); + void clientConnected(const QHostAddress& address); + void clientConnected(QTcpSocket* socket); + void clientDisconnected(QTcpSocket* socket); + void clientDisconnected(const QHostAddress& address); + +private Q_SLOTS: + void onConnectionClosed(); + +private: + QTcpServer *m_server; +}; + diff --git a/src/lib/lib.pro b/src/lib/lib.pro new file mode 100644 index 0000000..81af9ea --- /dev/null +++ b/src/lib/lib.pro @@ -0,0 +1,14 @@ +TEMPLATE = lib +TARGET = qmllive + + +DESTDIR = ../../libs +DEFINES += QMLLIVE_LIBRARY + +SOURCES += \ + qmllive.cpp + +HEADERS +=\ + qmllive_global.h \ + qmllive.h + diff --git a/src/lib/qmllive.cpp b/src/lib/qmllive.cpp new file mode 100644 index 0000000..65ffb52 --- /dev/null +++ b/src/lib/qmllive.cpp @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +#include "qmllive.h" + + +QmlLive::QmlLive() +{ +} diff --git a/src/lib/qmllive.h b/src/lib/qmllive.h new file mode 100644 index 0000000..f69a6e3 --- /dev/null +++ b/src/lib/qmllive.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#ifndef QMLLIVELIB_H +#define QMLLIVELIB_H + +#include "qmllive_global.h" + +class QMLLIVESHARED_EXPORT QmlLive +{ +public: + QmlLive(); +}; + +#endif // QMLLIVELIB_H diff --git a/src/lib/qmllive_global.h b/src/lib/qmllive_global.h new file mode 100644 index 0000000..cdad758 --- /dev/null +++ b/src/lib/qmllive_global.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#ifndef QMLLIVELIB_GLOBAL_H +#define QMLLIVELIB_GLOBAL_H + +#include <QtCore/qglobal.h> + +#if defined(QMLLIVE_LIBRARY) +# define QMLLIVESHARED_EXPORT Q_DECL_EXPORT +#else +# define QMLLIVESHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // QMLLIVELIB_GLOBAL_H diff --git a/src/livehubengine.cpp b/src/livehubengine.cpp new file mode 100644 index 0000000..3561053 --- /dev/null +++ b/src/livehubengine.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "livehubengine.h" +#include "watcher.h" + +#ifdef QMLLIVE_DEBUG +#define DEBUG qDebug() +#else +#define DEBUG if (0) qDebug() +#endif + +/*! + * \class LiveHubEngine + * \brief The LiveHubEngine class watches over a workspace and notifies a node on changes + * \group qmllive + * + * The live hub watches over a workspace and notifies a live node about changed files. A + * node can run on the same device or even on a remote device using a RemotePublisher. + */ + +/*! + * Standard constructor using \a parent as parent + */ +LiveHubEngine::LiveHubEngine(QObject *parent) + : QObject(parent) + , m_watcher(new Watcher(this)) + , m_filePublishingActive(false) +{ + connect(m_watcher, SIGNAL(directoriesChanged(QStringList)), this, SLOT(directoriesChanged(QStringList))); +} + +/*! + * Sets the workspace folder to watch over to \a path + */ +void LiveHubEngine::setWorkspace(const QString &path) +{ + m_watcher->setDirectory(path); + + emit workspaceChanged(path); +} + +/*! + * Returns the current workspace + */ +QString LiveHubEngine::workspace() const +{ + return m_watcher->directory(); +} + +/*! + * Sets the active document path to path. + * Emits activateDocument() with the workspace relative path. + */ +void LiveHubEngine::setActivePath(const QString &path) +{ + m_activePath = path; + emit activateDocument(m_watcher->relativeFilePath(path)); +} + +/*! + * Returns the active Document + */ +QString LiveHubEngine::activePath() const +{ + return m_activePath; +} + +/*! + * Handles watcher changes signals. + */ +void LiveHubEngine::directoriesChanged(const QStringList &changes) +{ + DEBUG << "LiveHubEngine::workspaceChanged: " << changes; + if (m_filePublishingActive) { + foreach (const QString& change, changes) { + publishDirectory(change, true); + } + } + + emit activateDocument(m_watcher->relativeFilePath(m_activePath)); +} + +/*! + * Publish the whole workspace to a connected node. + */ +void LiveHubEngine::publishWorkspace() +{ + if (!m_filePublishingActive) { return; } + QDirIterator iter(m_watcher->directory(), QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + publishDirectory(m_watcher->directory(), false); + while (iter.hasNext()) { + publishDirectory(iter.next(), false); + } +} + +/*! + * Publish the directory \a dirPath to a connected node. + */ +void LiveHubEngine::publishDirectory(const QString& dirPath, bool fileChange) +{ + if (!m_filePublishingActive) { return; } + QDirIterator iter(dirPath, QDir::Files); + while (iter.hasNext()) { + if (fileChange) + emit fileChanged(iter.next()); + else + emit publishFile(iter.next()); + } +} + +/*! + * Sets the file publishing to \a on + */ +void LiveHubEngine::setFilePublishingActive(bool on) +{ + m_filePublishingActive = on; +} + +/*! + * \fn void LiveHubEngine::workspaceChanged() + * Emits that the workspace changed + */ + +/*! + * \fn void LiveHubEngine::activateDocument(const QString& document) + * The document \a document is now active + */ + +/*! + * \fn void LiveHubEngine::sendDocument(const QString& document, const QByteArray& data) + * The Document \a document with the content \a data was sent + */ diff --git a/src/livehubengine.h b/src/livehubengine.h new file mode 100644 index 0000000..bf087ad --- /dev/null +++ b/src/livehubengine.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> + +class Watcher; +class ContentPluginFactory; + +class LiveHubEngine : public QObject +{ + Q_OBJECT +public: + explicit LiveHubEngine(QObject *parent = 0); + void setWorkspace(const QString& path); + QString workspace() const; + + QString activePath() const; +public Q_SLOTS: + void setActivePath(const QString& path); + void setFilePublishingActive(bool on); + void publishWorkspace(); +Q_SIGNALS: + void publishFile(const QString& document); + void fileChanged(const QString& document); + void activateDocument(const QString& document); + void workspaceChanged(const QString& workspace); +private Q_SLOTS: + void directoriesChanged(const QStringList& changes); +private: + void publishDirectory(const QString& dirPath, bool fileChange); +private: + Watcher *m_watcher; + bool m_filePublishingActive; + QString m_activePath; +}; + diff --git a/src/livenodeengine.cpp b/src/livenodeengine.cpp new file mode 100644 index 0000000..8bfeefe --- /dev/null +++ b/src/livenodeengine.cpp @@ -0,0 +1,477 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "livenodeengine.h" +#include "liveruntime.h" +#include "qmlhelper.h" +#include "contentpluginfactory.h" +#include "imageadapter.h" +#include "fontadapter.h" + +#include "QtQml/qqml.h" +#include "QtQuick/private/qquickpixmapcache_p.h" + +// TODO: create proxy configuration settings, controlled by command line and ui + +#ifdef QMLLIVE_DEBUG +#define DEBUG qDebug() +#else +#define DEBUG if (0) qDebug() +#endif + +/*! + * \class LiveNodeEngine + * \brief The LiveNodeEngine class instruments a qml viewer in cooperation with LiveHubEngine. + * \group qmllive + * + * LiveNodeEngine provides ways to reload qml documents based incoming requests + * from a hub. A hub can be connected via a local mode ( LocalPublisher) or + * remote mode (RemotePublisher with a RemoteReceiver). + * + * In Addition to showing qml-Files the LiveNodeEngine can be extended by plugins to show any other datatype. + * One need to set the Plugin path to the right destination and the LiveNodeEngine will load all the plugins + * it finds there. + * + * \sa {ContentPlugin Example} + */ + +/*! + * Standard constructor using \a parent as parent + */ +LiveNodeEngine::LiveNodeEngine(QObject *parent) + : QObject(parent) + , m_runtime(new LiveRuntime(this)) + , m_xOffset(0) + , m_yOffset(0) + , m_rotation(0) + , m_view(0) + , m_recreateView(0) + , m_delayReload(new QTimer(this)) + , m_mode(ReloadDocument) + , m_pluginFactory(new ContentPluginFactory(this)) + , m_activePlugin(0) + , m_reloadPlugins(false) +{ + m_delayReload->setInterval(250); + m_delayReload->setSingleShot(true); + connect(m_delayReload, SIGNAL(timeout()), this, SLOT(reloadDocument())); +} + +/*! + * Sets the view which should be used to \a view + */ + void LiveNodeEngine::setView(QQuickView *view) +{ + m_view = view; + m_view->rootContext()->setContextProperty("livert", m_runtime); + m_view->engine()->setOutputWarningsToStandardError(false); // log + m_view->engine()->setImportPathList(m_importPaths); + + connect(m_view->engine(), SIGNAL(warnings(QList<QQmlError>)), + this, SIGNAL(logErrors(QList<QQmlError>))); + connect(m_view, SIGNAL(statusChanged(QQuickView::Status)), + this, SLOT(onStatusChanged(QQuickView::Status))); + connect(m_view, SIGNAL(widthChanged(int)), + this, SLOT(onSizeChanged())); + connect(m_view, SIGNAL(heightChanged(int)), + this, SLOT(onSizeChanged())); +} + +void LiveNodeEngine::setXOffset(int offset) +{ + QQuickView* view = 0; + + if (m_view) + view = m_view; + if (m_recreateView) + view = m_recreateView; + if (view) + view->contentItem()->setX(offset); + + m_xOffset = offset; +} + +int LiveNodeEngine::xOffset() const +{ + return m_xOffset; +} + +void LiveNodeEngine::setYOffset(int offset) +{ + QQuickView* view = 0; + + if (m_view) + view = m_view; + if (m_recreateView) + view = m_recreateView; + if (view) + view->contentItem()->setY(offset); + + m_yOffset = offset; +} + +int LiveNodeEngine::yOffset() const +{ + return m_yOffset; +} + +void LiveNodeEngine::setRotation(int rotation) +{ + QQuickView* view = 0; + + if (m_view) + view = m_view; + if (m_recreateView) + view = m_recreateView; + if (view) { + view->contentItem()->setRotation(0); + view->contentItem()->setTransformOriginPoint(QPointF(view->width()/2, view->height()/2)); + view->contentItem()->setRotation(rotation); + } + + m_rotation = rotation; +} + +int LiveNodeEngine::rotation() const +{ + return m_rotation; +} + +void LiveNodeEngine::setUpdateMode(LiveNodeEngine::UpdateMode mode) +{ + m_mode = mode; +} + +LiveNodeEngine::UpdateMode LiveNodeEngine::updateMode() const +{ + return m_mode; +} + +/*! + * Loads the given \a url onto the qml view. Clears any caches and reloads + * the dummy data initially. + */ +void LiveNodeEngine::loadDocument(const QUrl& url) +{ + DEBUG << "LiveNodeEngine::loadDocument: " << url; + m_activeFile = url; + + if (!m_activeFile.isEmpty()) + reloadDocument(); +} + +void LiveNodeEngine::delayReload() +{ + m_delayReload->start(); +} + +/*! + * Sets the view which should be used to \a view + */ +void LiveNodeEngine::recreateView() +{ + if (m_windowComponent) + delete m_windowComponent; + if (m_windowObject) + delete m_windowObject; + + if (m_recreateView) { + //m_recreateView->setSource(QUrl()); + m_recreateView->engine()->clearComponentCache(); + delete m_recreateView; + if (m_reloadPlugins) + qmlClearTypeRegistrations(); + QQuickPixmap::purgeCache(); + } + + m_recreateView = initView(); + + setXOffset(m_xOffset); + setYOffset(m_yOffset); + + m_recreateView->rootContext()->setContextProperty("livert", m_runtime); + m_recreateView->engine()->setOutputWarningsToStandardError(false); // log + if (!m_importPaths.isEmpty()) + m_recreateView->engine()->setImportPathList(m_importPaths); + + m_recreateView->engine()->clearComponentCache(); + QmlHelper::loadDummyData(m_recreateView, m_workspace.absolutePath()); + + connect(m_recreateView->engine(), SIGNAL(warnings(QList<QQmlError>)), + this, SIGNAL(logErrors(QList<QQmlError>))); + connect(m_recreateView, SIGNAL(statusChanged(QQuickView::Status)), + this, SLOT(onStatusChanged(QQuickView::Status))); + connect(m_recreateView, SIGNAL(widthChanged(int)), + this, SLOT(onSizeChanged())); + connect(m_recreateView, SIGNAL(heightChanged(int)), + this, SLOT(onSizeChanged())); +} + +void LiveNodeEngine::checkQmlFeatures(QQuickView *view) +{ + foreach (QString importPath, view->engine()->importPathList()) { + QDir dir(importPath); + if (dir.exists("QtQuick/Controls") && + dir.exists("QtQuick/Layouts") && + dir.exists("QtQuick/Dialogs")) { + m_quickFeatures |= ContentAdapterInterface::QtQuickControls; + } + } +} + +/*! + * Reloads the qml view source. + */ +void LiveNodeEngine::reloadDocument() +{ + QQuickView *view = 0; + + if (m_mode == RecreateView) { + recreateView(); + + view = m_recreateView; + } else { + view = m_view; + view->setSource(QUrl()); + } + + checkQmlFeatures(view); + + emit logClear(); + //emit logIgnoreMessages(true); + + QUrl url = queryDocumentViewer(m_activeFile); + QQmlEngine* engine = view->engine(); + m_windowComponent = new QQmlComponent(engine); + + m_windowComponent->loadUrl(url); + + m_windowObject = m_windowComponent->create(); + QQuickWindow *window = qobject_cast<QQuickWindow *>(m_windowObject); + if (window) { + engine->setIncubationController(window->incubationController()); + window->show(); + } else { + view->setContent(url, m_windowComponent, m_windowObject); + } + + //emit logIgnoreMessages(false); + + QList<QQmlError> errors = view->errors(); + if (!errors.isEmpty()) { + emit logErrors(errors); + if (m_quickFeatures.testFlag(ContentAdapterInterface::QtQuickControls)) + view->setSource(QUrl("qrc:/livert/error_qt5_controls.qml")); + view->setSource(QUrl("qrc:/livert/error_qt5.qml")); + } + + if (m_mode == RecreateView) + view->setVisible(true); + + if (m_activePlugin || (view->rootObject() && QSize(view->rootObject()->width(), view->rootObject()->height()).isEmpty())) { + view->setResizeMode(QQuickView::SizeRootObjectToView); + } else { + view->setResizeMode(QQuickView::SizeViewToRootObject); + } +} + + +/*! + * Allows to adapt a \a url to display not native qml documents (e.g. images). + */ +QUrl LiveNodeEngine::queryDocumentViewer(const QUrl& url) +{ + initPlugins(); + + foreach (ContentAdapterInterface* adapter, m_plugins) { + if (adapter->canAdapt(url)) { + adapter->cleanUp(); + adapter->setAvailableFeatures(m_quickFeatures); + + m_activePlugin = adapter; + + if (m_mode == RecreateView) + return adapter->adapt(url, m_recreateView->rootContext()); + else + return adapter->adapt(url, m_view->rootContext()); + } + } + + m_activePlugin = 0; + + return url; +} + +/*! + * Sets the document \a document to be shown + * + */ +void LiveNodeEngine::setActiveDocument(const QString &document) +{ + QUrl url; + if (!document.isEmpty()) { + url = QUrl::fromLocalFile(m_workspace.absoluteFilePath(document)); + } + + loadDocument(url); + emit activateDocument(document); +} + +/*! + * Sets the current workspace to \a path. Documents location will be adjusted based on + * this workspace path. + */ +void LiveNodeEngine::setWorkspace(const QString &path) +{ + m_workspace = QDir(path); +} + +void LiveNodeEngine::setImportPaths(const QStringList &paths) +{ + m_importPaths = paths; + + if (m_view) + m_view->engine()->setImportPathList(paths); +} + +QStringList LiveNodeEngine::importPaths() const +{ + return m_importPaths; +} + +/*! + * Sets the pluginPath to \a path. + * + * The pluginPath will be used to load QmlLive plugins + * \sa {ContentPlugin Example} + */ +void LiveNodeEngine::setPluginPath(const QString &path) +{ + m_pluginFactory->setPluginPath(path); +} + +/*! + * Returns the current pluginPath + */ +QString LiveNodeEngine::pluginPath() const +{ + return m_pluginFactory->pluginPath(); +} + +/*! + * Returns the current active document url. + */ +QUrl LiveNodeEngine::activeDocument() const +{ + return m_activeFile; +} + +ContentAdapterInterface *LiveNodeEngine::activePlugin() const +{ + return m_activePlugin; +} + +void LiveNodeEngine::setReloadPluginsEnabled(bool enabled) +{ + m_reloadPlugins = enabled; +} + +bool LiveNodeEngine::isReloadPluginsEnabled() const +{ + return m_reloadPlugins; +} + +/*! + * Loads all plugins found in the Pluginpath + */ +void LiveNodeEngine::initPlugins() +{ + if (m_plugins.isEmpty()) { + m_pluginFactory->load(); + m_plugins.append(m_pluginFactory->plugins()); + m_plugins.append(new ImageAdapter(this)); + m_plugins.append(new FontAdapter(this)); + } +} + +void LiveNodeEngine::onStatusChanged(QQuickView::Status status) +{ + if (status == QQuickView::Ready || + status == QQuickView::Error) { + emit documentLoaded(); + } +} + +QQuickView *LiveNodeEngine::initView() +{ + QQuickView* view = new QQuickView(); + emit viewChanged(view); + return view; +} + +void LiveNodeEngine::onSizeChanged() +{ + int width = -1, height = -1; + + if (m_mode == RecreateView && m_recreateView) { + width = m_recreateView->width(); + height = m_recreateView->height(); + } else if (m_mode == ReloadDocument && m_view) { + width = m_view->width(); + height = m_view->height(); + } + + if (width != -1 && height != -1) { + m_runtime->setScreenWidth(width); + m_runtime->setScreenHeight(height); + } + + setRotation(m_rotation); +} + +/*! + * \fn void LiveNodeEngine::activateDocument(const QString& document); + * The document \a document was activated + */ + +/*! + * \fn void LiveNodeEngine::logClear(); + * Requested to clear the log + */ + +/*! + * \fn void LiveNodeEngine::logIgnoreMessages(bool); + * Requsted to ignore the Messages when \a on is true + */ + +/*! + * \fn void LiveNodeEngine::logErrors(const QList<QQmlError> &errors); + * Log the Errors \a errors + */ diff --git a/src/livenodeengine.h b/src/livenodeengine.h new file mode 100644 index 0000000..f9d5f6f --- /dev/null +++ b/src/livenodeengine.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> +#include <QtQuick> + +#include "contentadapterinterface.h" + +class IpcPeer; +class LiveRuntime; +class ContentPluginFactory; + +class LiveNodeEngine : public QObject +{ + Q_OBJECT +public: + + enum UpdateMode { + ReloadDocument, + RecreateView, + RecreateProcess + }; + Q_ENUMS(UpdateMode) + + explicit LiveNodeEngine(QObject *parent = 0); + virtual void setView(QQuickView* view); + + int xOffset() const; + int yOffset() const; + int rotation() const; + + void setUpdateMode(LiveNodeEngine::UpdateMode mode); + LiveNodeEngine::UpdateMode updateMode() const; + + void setWorkspace(const QString& path); + + void setImportPaths(const QStringList& paths); + QStringList importPaths() const; + + void setPluginPath(const QString& path); + QString pluginPath() const; + + QUrl activeDocument() const; + ContentAdapterInterface *activePlugin() const; + bool isReloadPluginsEnabled() const; + +public Q_SLOTS: + + void setXOffset(int offset); + void setYOffset(int offset); + void setRotation(int rotation); + void setReloadPluginsEnabled(bool enabled); + void setActiveDocument(const QString& document); + void loadDocument(const QUrl& url); + void delayReload(); + virtual void reloadDocument(); +Q_SIGNALS: + void activateDocument(const QString& document); + void logClear(); + void logIgnoreMessages(bool on); + void documentLoaded(); + void viewChanged(QQuickView *view); + void logErrors(const QList<QQmlError> &errors); + + +protected: + virtual QQuickView* initView(); + virtual void initPlugins(); + QList<ContentAdapterInterface*> m_plugins; + QUrl m_activeFile; + LiveRuntime *m_runtime; +private Q_SLOTS: + void onStatusChanged(QQuickView::Status status); + void onSizeChanged(); + + void recreateView(); + + void checkQmlFeatures(QQuickView *view); + +private: + QUrl queryDocumentViewer(const QUrl& url); +private: + int m_xOffset; + int m_yOffset; + int m_rotation; + + IpcPeer *m_ipc; + QQuickView *m_view; + QQuickView *m_recreateView; + QPointer<QQmlComponent> m_windowComponent; + QPointer<QObject> m_windowObject; + QDir m_workspace; + QTimer *m_delayReload; + QStringList m_importPaths; + + UpdateMode m_mode; + + ContentPluginFactory* m_pluginFactory; + ContentAdapterInterface* m_activePlugin; + + ContentAdapterInterface::Features m_quickFeatures; + + bool m_reloadPlugins; +}; + diff --git a/src/livert.qrc b/src/livert.qrc new file mode 100644 index 0000000..6c9d2ce --- /dev/null +++ b/src/livert.qrc @@ -0,0 +1,18 @@ +<RCC> + <qresource prefix="/"> + <file>livert/error_qt5.qml</file> + <file>livert/logo.png</file> + <file>livert/imageviewer_qt5.qml</file> + <file>images/favicon.png</file> + <file>livert/folderview_qt5.qml</file> + <file>livert/fontviewer_qt5.qml</file> + <file>livert/no.png</file> + <file>livert/error_qt5_controls.qml</file> + <file>livert/folderview_qt5_controls.qml</file> + <file>livert/fontviewer_qt5_controls.qml</file> + <file>livert/imageviewer_qt5_controls.qml</file> + <file>images/icon_online.png</file> + <file>images/icon_offline.png</file> + <file>images/icon_failover.png</file> + </qresource> +</RCC> diff --git a/src/livert/error_qt5.qml b/src/livert/error_qt5.qml new file mode 100644 index 0000000..8a48a8d --- /dev/null +++ b/src/livert/error_qt5.qml @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +import QtQuick 2.0 + +Rectangle { + width: 800 + height: 480 + + SystemPalette { + id: palette; + colorGroup: SystemPalette.Active + } + color: palette.base + + Image { + anchors.fill: parent; + source: "logo.png" + fillMode: Image.Tile + opacity: 0.5 + } + Text { + anchors.centerIn: parent + text: qsTr("An error occurred - please check the Log Output pane.") + font.pointSize: 20 + font.bold: true + color: palette.text + } +} diff --git a/src/livert/error_qt5_controls.qml b/src/livert/error_qt5_controls.qml new file mode 100644 index 0000000..fc89ad3 --- /dev/null +++ b/src/livert/error_qt5_controls.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +import QtQuick 2.1 +import QtQuick.Controls 1.0 + +Rectangle { + width: 800 + height: 480 + + SystemPalette { + id: palette; + colorGroup: SystemPalette.Active + } + color: palette.base + + Image { + anchors.fill: parent; + source: "logo.png" + fillMode: Image.Tile + opacity: 0.5 + } + Label { + anchors.fill: parent + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: qsTr("An error occurred - please check the Log Output pane. (Controls)") + wrapMode: Text.WordWrap + font.pointSize: 20 + font.bold: true + color: palette.text + } +} diff --git a/src/livert/folderview_qt5.qml b/src/livert/folderview_qt5.qml new file mode 100644 index 0000000..54a4e33 --- /dev/null +++ b/src/livert/folderview_qt5.qml @@ -0,0 +1,324 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +import QtQuick 2.0 + +Item { + id: root + width: livert.screenWidth + height: livert.screenHeight + + property color backgroundColor: '#666' + property color textColor: '#fff' + + Rectangle { + anchors.fill: parent + color: root.backgroundColor + } + + Rectangle { + id: header + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + height: 32 + + z: 2 + + color: "#E0E0E0" + + Rectangle { + } + + Row { + anchors.left: parent.left + anchors.leftMargin: 8 + width: childrenRect.width + height: 24 + anchors.verticalCenter: parent.verticalCenter + Repeater { + model: [ + { bg: '#000', text: '#fff' }, + { bg: '#666', text: '#000' }, + { bg: '#fff', text: '#000' } + ] + Rectangle { + color: modelData.bg + width: 24 + height: parent.height + MouseArea { + anchors.fill: parent + onClicked: { + root.backgroundColor = modelData.bg + root.textColor = modelData.text + } + } + } + } + } + + Item { + id: slider + anchors.right: parent.right + anchors.rightMargin: 8 + anchors.top: parent.top + anchors.bottom: parent.bottom + + property real minValue: 80 + property real maxValue: 300 + //Math.min workaround to prevent that it its Infinity (otherwise the Selection item doesn't work anymore) + property real value: Math.min((handle.x / line.width) * (maxValue - minValue) + minValue, maxValue) + + width: 200 + + Rectangle { + id: line + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + color: "black" + + height: 2 + } + + Rectangle { + id: handle + + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: 5 + x: parent.width/2 + width: 12 + + border.width: 2 + border.color: "black" + + color: "#e0e0e0" + + MouseArea { + anchors.fill: parent + + property real xPos + + onClicked: xPos = mouse.x + + onPositionChanged: { + var delta = mouse.x - xPos - handle.width / 2 + var newPos = handle.x + delta + if (newPos + handle.width / 2> 0 && newPos < line.width - handle.width / 2) + handle.x = newPos + } + } + } + } + } + + GridView { + id: grid + + anchors.top: header.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + + anchors.margins: 30 + + cellWidth: slider.value + cellHeight: slider.value + + keyNavigationWraps: true + + focus: true + + model: files + + delegate: FocusScope { + width: grid.cellWidth - 4 + height: grid.cellHeight - 4 + + + Item { + id: delegate + anchors.fill: parent + anchors.margins: 4 + + function loadDocument() { + adapter.loadDocument(path + "/" + modelData) + } + + focus: true + + Keys.onReturnPressed: delegate.loadDocument() + Keys.onLeftPressed: grid.moveCurrentIndexLeft() + Keys.onRightPressed: grid.moveCurrentIndexRight() + Keys.onUpPressed: grid.moveCurrentIndexUp() + Keys.onDownPressed: grid.moveCurrentIndexDown() + + Image { + id: image + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + height: 0.8 * width + + source: "image://qmlLiveDirectoryPreview/" + path + "/" + modelData + + fillMode: Image.PreserveAspectFit + sourceSize.width: slider.maxValue + sourceSize.height: slider.maxValue + + asynchronous: true + cache: false + } + + Text { + id: label + anchors.top: image.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + + text: modelData + color: root.textColor + + textFormat: Text.PlainText + elide: Text.ElideMiddle + horizontalAlignment: Text.AlignHCenter + } + + MouseArea { + anchors.fill: parent + + onClicked: grid.currentIndex = index + onDoubleClicked: delegate.loadDocument() + } + } + } + + highlight: FocusScope { + id: highlight + Rectangle { + width: grid.cellWidth + height: grid.cellHeight + color: "#33B5E5" + opacity: 0.5 + } + } + } + + Item { + id: scrollBar + + width: 15; height: grid.height + anchors.top: header.bottom + anchors.right: parent.right + anchors.rightMargin: 3 + anchors.bottom: parent.bottom + + // The properties that define the scrollbar's state. + // position and pageSize are in the range 0.0 - 1.0. They are relative to the + // height of the page, i.e. a pageSize of 0.5 means that you can see 50% + // of the height of the view. + // orientation can be either Qt.Vertical or Qt.Horizontal + property Flickable flickable: grid + property real position: scrollBar.orientation == Qt.Vertical ? flickable.visibleArea.yPosition : flickable.visibleArea.xPosition + property real pageSize: scrollBar.orientation == Qt.Vertical ? flickable.visibleArea.heightRatio : flickable.visibleArea.widthRatio + property int orientation : Qt.Vertical + property alias enableDrag: mouseArea.enabled + + visible: pageSize != 1 + + // A light, semi-transparent background + Rectangle { + id: background + anchors.fill: parent + radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1) + color: "white" + opacity: 0.3 + } + + // Size the bar to the required size, depending upon the orientation. + Rectangle { + id: bar + x: scrollBar.orientation == Qt.Vertical ? 1 : (scrollBar.position * (scrollBar.width-2) + 1) + y: scrollBar.orientation == Qt.Vertical ? (scrollBar.position * (scrollBar.height-2) + 1) : 1 + width: scrollBar.orientation == Qt.Vertical ? (parent.width-2) : (scrollBar.pageSize * (scrollBar.width-2)) + height: scrollBar.orientation == Qt.Vertical ? (scrollBar.pageSize * (scrollBar.height-2)) : (parent.height-2) + radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1) + color: "black" + opacity: 0.7 + } + + MouseArea { + id: mouseArea + anchors.fill: parent + + property variant pressedPos + property bool drag: true + onPressed: { + pressedPos = mapToItem(bar, mouseX, mouseY) + if (pressedPos.x >= 0 && pressedPos.x <= bar.width && + pressedPos.y >= 0 && pressedPos.y <= bar.height) + drag = true + } + onReleased: drag = false + + onPositionChanged: { + if (drag) { + if (scrollBar.orientation == Qt.Vertical) { + var newPos =((mouseY - pressedPos.y -1 ) / (scrollBar.height-2)) * scrollBar.flickable.contentHeight + if (newPos < 0) + scrollBar.flickable.contentY = 0 + else if (newPos > (scrollBar.flickable.contentHeight - scrollBar.flickable.height)) + scrollBar.flickable.contentY = (scrollBar.flickable.contentHeight - scrollBar.flickable.height) + else + scrollBar.flickable.contentY = newPos + } else { + var newPos =((mouseX - pressedPos.x -1 ) / (scrollBar.width-2)) * scrollBar.flickable.contentWidth + if (newPos < 0) + scrollBar.flickable.contentX = 0 + else if (newPos > (scrollBar.flickable.contentWidth - scrollBar.flickable.width)) + scrollBar.flickable.contentX = (scrollBar.flickable.contentWidth - scrollBar.flickable.width) + else + scrollBar.flickable.contentX = newPos + } + } + } + } + } + + Component.onCompleted: { + grid.forceActiveFocus(); + } +} diff --git a/src/livert/folderview_qt5_controls.qml b/src/livert/folderview_qt5_controls.qml new file mode 100644 index 0000000..ef8b1af --- /dev/null +++ b/src/livert/folderview_qt5_controls.qml @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import QtQuick.Layouts 1.0 + +Item { + id: root + width: livert.screenWidth + height: livert.screenHeight + + property color backgroundColor: '#666' + property color textColor: '#fff' + + Rectangle { + anchors.fill: parent + color: root.backgroundColor + } + + Item { + id: header + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: 32 + + z: 0 + + Rectangle { + anchors.fill: parent + color: "#E0E0E0" + } + RowLayout { + anchors.fill: parent + anchors.leftMargin: 8 + anchors.rightMargin: 8 + Repeater { + model: [ + { bg: '#000', text: '#fff' }, + { bg: '#666', text: '#000' }, + { bg: '#fff', text: '#000' } + ] + Button { + text: " " + Rectangle { + anchors.fill: parent + anchors.margins: 2 + color: modelData.bg + } + onClicked: { + root.backgroundColor = modelData.bg + root.textColor = modelData.text + } + } + } + Item { + width: 16; height: 16 + Layout.fillWidth: true + } + + Slider { + id: slider + anchors.verticalCenter: parent.verticalCenter + maximumValue: 300 + value: 190 + minimumValue: 80 + } + } + + } + + + Component { + id: gridDelegate + FocusScope { + id: delegateContainer + width: grid.cellWidth - 4 + height: grid.cellHeight - 4 + Item { + id: delegate + anchors.fill: parent + anchors.margins: 4 + + function loadDocument() { + adapter.loadDocument(path + "/" + modelData) + } + + focus: true + + Keys.onReturnPressed: delegate.loadDocument() + Keys.onLeftPressed: grid.moveCurrentIndexLeft() + Keys.onRightPressed: grid.moveCurrentIndexRight() + Keys.onUpPressed: grid.moveCurrentIndexUp() + Keys.onDownPressed: grid.moveCurrentIndexDown() + + Image { + id: image + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + height: 0.8 * width + + source: "image://qmlLiveDirectoryPreview/" + path + "/" + modelData + + fillMode: Image.PreserveAspectFit + sourceSize.width: slider.maximumValue + sourceSize.height: slider.maximumValue + + asynchronous: true + cache: false + } + + Text { + id: label + anchors.top: image.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + + text: modelData + color: root.textColor + + textFormat: Text.PlainText + elide: Text.ElideMiddle + horizontalAlignment: Text.AlignHCenter + } + + MouseArea { + anchors.fill: parent + + onClicked: grid.currentIndex = index; + onDoubleClicked: delegate.loadDocument() + } + } + } + } + ScrollView { + id: scrollView + anchors.top: header.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + + //anchors.margins: 30 + GridView { + id: grid + + + cellWidth: slider.value + cellHeight: slider.value + + keyNavigationWraps: true + + focus: true + + model: files + + delegate: gridDelegate + + highlight: Item { + id: highlight + Rectangle { + width: grid.cellWidth + height: grid.cellHeight + color: "#33B5E5" + opacity: 0.5 + } + } + } + } + + Component.onCompleted: { + scrollView.forceActiveFocus(); + } +} diff --git a/src/livert/fontviewer_qt5.qml b/src/livert/fontviewer_qt5.qml new file mode 100644 index 0000000..cfe497b --- /dev/null +++ b/src/livert/fontviewer_qt5.qml @@ -0,0 +1,387 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +import QtQuick 2.0 + +Rectangle { + id: root + width: livert.screenWidth + height: livert.screenHeight + + property alias testText: textInput.text + property int pointSize: 12 + property var defaultWeights:[ + { name: "Light", weight: Font.Light }, + { name: "Regular", weight: Font.Normal }, + { name: "DemiBold", weight: Font.DemiBold }, + { name: "Bold", weight: Font.Bold }, + { name: "Black", weight: Font.Black }, + ] + + property bool showAllWeights: false + + Rectangle { + id: header + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + height: 32 + + z: 2 + + color: "#E0E0E0" + + Row { + anchors.centerIn: parent + + spacing: 2 + + height: 20 + width: parent.width + + Text { + width: 120 + height: 20 + + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + text: "Font Size: " + root.pointSize + "pt " + } + + Rectangle { + width: 20 + height: 20 + + Text { + anchors.fill: parent + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: "+" + } + + MouseArea { + anchors.fill: parent + + onClicked: pointSize += 2 + } + } + + Rectangle { + width: 20 + height: 20 + + Text { + anchors.fill: parent + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: "-" + } + + MouseArea { + anchors.fill: parent + + onClicked: pointSize -= 2 + } + } + + Text { + width: 150 + height: 20 + + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + text: "Example Text: " + } + + Rectangle { + height: 20 + width: 300 + + clip: true + + TextInput { + id: textInput + + anchors.fill: parent + anchors.margins: 1 + + focus: true + + text: "The quick brown fox jumps over the lazy dog" + } + } + + Text { + width: 250 + height: 20 + + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + text: "Show all QML font styles: " + } + + Rectangle { + height: 20 + width: 20 + + border.width: 1 + + Rectangle { + id: checker + anchors.centerIn: parent + width: 15 + height: 15 + color: "black" + + visible: showAllWeights + } + + MouseArea { + anchors.fill: parent + + onClicked: showAllWeights = !showAllWeights + } + } + } + } + + ListView { + id: list + anchors.top: header.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + + model: styles + + delegate: ListView { + + id: familyDelegate + + property var style: styles[index] + + interactive: false + + width: parent.width + height: childrenRect.height; + + model: !showAllWeights ? style.weights : defaultWeights + + delegate: Column { + + width: root.width + height: childrenRect.height + 20 + + anchors.margins: 2 + + spacing: 2 + + property string name: showAllWeights ? modelData.name : familyDelegate.style.weights[index].name + property int weight: showAllWeights ? modelData.weight : familyDelegate.style.weights[index].weight + + Text { + text: familyDelegate.style.family + ", " + name + } + + Rectangle { + color: "black" + height: 1 + width: root.width + } + + Text { + id: exampleText + font.pointSize: root.pointSize + font.family: familyDelegate.style.family + font.weight: weight + text: "abcdefghijklmnopqrstuvwxyz" + } + + Text { + font.pointSize: root.pointSize + font.family: familyDelegate.style.family + font.weight: weight + text: "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + } + + Text { + font.pointSize: root.pointSize + font.family: familyDelegate.style.family + font.weight: weight + text: "0123456789.:;(*!?'/\\\")%&-+@~#<>{}[]" + } + + Rectangle { + color: "black" + height: 1 + width: root.width + } + + Text { + font.pointSize: 6 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 8 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 10 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 18 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 24 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 30 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 36 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 42 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + } + } + } + + Item { + id: scrollBar + + width: 15; height: list.height + anchors.top: header.bottom + anchors.right: parent.right + anchors.rightMargin: 3 + anchors.bottom: parent.bottom + + // The properties that define the scrollbar's state. + // position and pageSize are in the range 0.0 - 1.0. They are relative to the + // height of the page, i.e. a pageSize of 0.5 means that you can see 50% + // of the height of the view. + // orientation can be either Qt.Vertical or Qt.Horizontal + property Flickable flickable: list + property real position: scrollBar.orientation == Qt.Vertical ? flickable.visibleArea.yPosition : flickable.visibleArea.xPosition + property real pageSize: scrollBar.orientation == Qt.Vertical ? flickable.visibleArea.heightRatio : flickable.visibleArea.widthRatio + property int orientation : Qt.Vertical + property alias enableDrag: mouseArea.enabled + + visible: pageSize != 1 + + // A light, semi-transparent background + Rectangle { + id: background + anchors.fill: parent + radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1) + color: "white" + opacity: 0.3 + } + + // Size the bar to the required size, depending upon the orientation. + Rectangle { + id: bar + x: scrollBar.orientation == Qt.Vertical ? 1 : (scrollBar.position * (scrollBar.width-2) + 1) + y: scrollBar.orientation == Qt.Vertical ? (scrollBar.position * (scrollBar.height-2) + 1) : 1 + width: scrollBar.orientation == Qt.Vertical ? (parent.width-2) : (scrollBar.pageSize * (scrollBar.width-2)) + height: scrollBar.orientation == Qt.Vertical ? (scrollBar.pageSize * (scrollBar.height-2)) : (parent.height-2) + radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1) + color: "black" + opacity: 0.7 + } + + MouseArea { + id: mouseArea + anchors.fill: parent + + property variant pressedPos + property bool drag: true + onPressed: { + pressedPos = mapToItem(bar, mouseX, mouseY) + if (pressedPos.x >= 0 && pressedPos.x <= bar.width && + pressedPos.y >= 0 && pressedPos.y <= bar.height) + drag = true + } + onReleased: drag = false + + onPositionChanged: { + if (drag) { + if (scrollBar.orientation == Qt.Vertical) { + var newPos =((mouseY - pressedPos.y -1 ) / (scrollBar.height-2)) * scrollBar.flickable.contentHeight + if (newPos < 0) + scrollBar.flickable.contentY = 0 + else if (newPos > (scrollBar.flickable.contentHeight - scrollBar.flickable.height)) + scrollBar.flickable.contentY = (scrollBar.flickable.contentHeight - scrollBar.flickable.height) + else + scrollBar.flickable.contentY = newPos + } else { + var newPos =((mouseX - pressedPos.x -1 ) / (scrollBar.width-2)) * scrollBar.flickable.contentWidth + if (newPos < 0) + scrollBar.flickable.contentX = 0 + else if (newPos > (scrollBar.flickable.contentWidth - scrollBar.flickable.width)) + scrollBar.flickable.contentX = (scrollBar.flickable.contentWidth - scrollBar.flickable.width) + else + scrollBar.flickable.contentX = newPos + } + } + } + } + } +} diff --git a/src/livert/fontviewer_qt5_controls.qml b/src/livert/fontviewer_qt5_controls.qml new file mode 100644 index 0000000..8bfa7f9 --- /dev/null +++ b/src/livert/fontviewer_qt5_controls.qml @@ -0,0 +1,350 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +import QtQuick 2.0 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import QtQuick.Layouts 1.0 + +Rectangle { + id: root + width: livert.screenWidth + height: livert.screenHeight + + property alias testText: textInput.text + property alias pointSize: pointSizeSpinBox.value + property var defaultWeights:[ + { name: "Light", weight: Font.Light }, + { name: "Regular", weight: Font.Normal }, + { name: "DemiBold", weight: Font.DemiBold }, + { name: "Bold", weight: Font.Bold }, + { name: "Black", weight: Font.Black }, + ] + + property alias showAllWeights: showAllWeightsCheckBox.checked + + Rectangle { + id: header + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + height: 32 + + z: 2 + + color: "#E0E0E0" + + RowLayout { + anchors.fill: parent + anchors.leftMargin: 8 + anchors.rightMargin: 8 + + Label { + width: 120 + height: 20 + + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + text: "Font Size:" + } + + SpinBox { + id: pointSizeSpinBox + suffix: "pt" + stepSize: 2 + value: 12 + minimumValue: 0 + maximumValue: 50 + + Layout.preferredWidth: 60 + } + + Label { + width: 150 + height: 20 + + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + text: "Example Text: " + } + + TextField { + id: textInput + + height: 20 + Layout.preferredWidth: 600 + + readOnly: false + + text: "The quick brown fox jumps over the lazy dog" + + focus: true + } + + Label { + width: 250 + height: 20 + + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + text: "Show all QML font styles: " + } + + CheckBox { + id: showAllWeightsCheckBox + height: 20 + width: 20 + } + + Item { + width: 16; height: 16 + Layout.fillWidth: true + } + + } + } + + ScrollView { + anchors.top: header.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + + ListView { + id: list + + model: styles + + delegate: ListView { + + id: familyDelegate + + property var style: styles[index] + + interactive: false + + width: parent.width + height: childrenRect.height; + + model: !showAllWeights ? style.weights : defaultWeights + + delegate: Column { + + width: root.width + height: childrenRect.height + 20 + + anchors.margins: 2 + + spacing: 2 + + property string name: showAllWeights ? modelData.name : familyDelegate.style.weights[index].name + property int weight: showAllWeights ? modelData.weight : familyDelegate.style.weights[index].weight + + Text { + text: familyDelegate.style.family + ", " + name + } + + Rectangle { + color: "black" + height: 1 + width: root.width + } + + Text { + id: exampleText + font.pointSize: root.pointSize + font.family: familyDelegate.style.family + font.weight: weight + text: "abcdefghijklmnopqrstuvwxyz" + } + + Text { + font.pointSize: root.pointSize + font.family: familyDelegate.style.family + font.weight: weight + text: "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + } + + Text { + font.pointSize: root.pointSize + font.family: familyDelegate.style.family + font.weight: weight + text: "0123456789.:;(*!?'/\\\")%&-+@~#<>{}[]" + } + + Rectangle { + color: "black" + height: 1 + width: root.width + } + + Text { + font.pointSize: 6 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 8 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 10 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 18 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 24 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 30 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 36 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + + Text { + font.pointSize: 42 + font.family: familyDelegate.style.family + font.weight: weight + text: "(" + font.pointSize + "pt)" + testText + } + } + } + } + + } + +// Item { +// id: scrollBar + +// width: 15; height: list.height +// anchors.top: header.bottom +// anchors.right: parent.right +// anchors.rightMargin: 3 +// anchors.bottom: parent.bottom + +// // The properties that define the scrollbar's state. +// // position and pageSize are in the range 0.0 - 1.0. They are relative to the +// // height of the page, i.e. a pageSize of 0.5 means that you can see 50% +// // of the height of the view. +// // orientation can be either Qt.Vertical or Qt.Horizontal +// property Flickable flickable: list +// property real position: scrollBar.orientation == Qt.Vertical ? flickable.visibleArea.yPosition : flickable.visibleArea.xPosition +// property real pageSize: scrollBar.orientation == Qt.Vertical ? flickable.visibleArea.heightRatio : flickable.visibleArea.widthRatio +// property int orientation : Qt.Vertical +// property alias enableDrag: mouseArea.enabled + +// visible: pageSize != 1 + +// // A light, semi-transparent background +// Rectangle { +// id: background +// anchors.fill: parent +// radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1) +// color: "white" +// opacity: 0.3 +// } + +// // Size the bar to the required size, depending upon the orientation. +// Rectangle { +// id: bar +// x: scrollBar.orientation == Qt.Vertical ? 1 : (scrollBar.position * (scrollBar.width-2) + 1) +// y: scrollBar.orientation == Qt.Vertical ? (scrollBar.position * (scrollBar.height-2) + 1) : 1 +// width: scrollBar.orientation == Qt.Vertical ? (parent.width-2) : (scrollBar.pageSize * (scrollBar.width-2)) +// height: scrollBar.orientation == Qt.Vertical ? (scrollBar.pageSize * (scrollBar.height-2)) : (parent.height-2) +// radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1) +// color: "black" +// opacity: 0.7 +// } + +// MouseArea { +// id: mouseArea +// anchors.fill: parent + +// property variant pressedPos +// property bool drag: true +// onPressed: { +// pressedPos = mapToItem(bar, mouseX, mouseY) +// if (pressedPos.x >= 0 && pressedPos.x <= bar.width && +// pressedPos.y >= 0 && pressedPos.y <= bar.height) +// drag = true +// } +// onReleased: drag = false + +// onPositionChanged: { +// if (drag) { +// if (scrollBar.orientation == Qt.Vertical) { +// var newPos =((mouseY - pressedPos.y -1 ) / (scrollBar.height-2)) * scrollBar.flickable.contentHeight +// if (newPos < 0) +// scrollBar.flickable.contentY = 0 +// else if (newPos > (scrollBar.flickable.contentHeight - scrollBar.flickable.height)) +// scrollBar.flickable.contentY = (scrollBar.flickable.contentHeight - scrollBar.flickable.height) +// else +// scrollBar.flickable.contentY = newPos +// } else { +// var newPos =((mouseX - pressedPos.x -1 ) / (scrollBar.width-2)) * scrollBar.flickable.contentWidth +// if (newPos < 0) +// scrollBar.flickable.contentX = 0 +// else if (newPos > (scrollBar.flickable.contentWidth - scrollBar.flickable.width)) +// scrollBar.flickable.contentX = (scrollBar.flickable.contentWidth - scrollBar.flickable.width) +// else +// scrollBar.flickable.contentX = newPos +// } +// } +// } +// } +// } +} diff --git a/src/livert/imageviewer_qt5.qml b/src/livert/imageviewer_qt5.qml new file mode 100644 index 0000000..321dec5 --- /dev/null +++ b/src/livert/imageviewer_qt5.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +import QtQuick 2.0 + +Item { + id: root + width: 480; height: 272 + Rectangle { + anchors.fill: parent + color: imageViewerBackgroundColor + } + Image { + id: image + anchors.centerIn: parent + source: imageViewerSource + } + + Text { + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.margins: 4 + color: '#ffffff' + text: image.width + "x" + image.height + } +} diff --git a/src/livert/imageviewer_qt5_controls.qml b/src/livert/imageviewer_qt5_controls.qml new file mode 100644 index 0000000..321dec5 --- /dev/null +++ b/src/livert/imageviewer_qt5_controls.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +import QtQuick 2.0 + +Item { + id: root + width: 480; height: 272 + Rectangle { + anchors.fill: parent + color: imageViewerBackgroundColor + } + Image { + id: image + anchors.centerIn: parent + source: imageViewerSource + } + + Text { + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.margins: 4 + color: '#ffffff' + text: image.width + "x" + image.height + } +} diff --git a/src/livert/logo.png b/src/livert/logo.png Binary files differnew file mode 100644 index 0000000..347df0e --- /dev/null +++ b/src/livert/logo.png diff --git a/src/livert/no.png b/src/livert/no.png Binary files differnew file mode 100644 index 0000000..8410421 --- /dev/null +++ b/src/livert/no.png diff --git a/src/liveruntime.cpp b/src/liveruntime.cpp new file mode 100644 index 0000000..d909896 --- /dev/null +++ b/src/liveruntime.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "liveruntime.h" + +// TODO: create a variant model for dynamic passing of key value pairs with notify +// TODO: create support for background and overlay layer image files livert.background, livert.overlay + +/*! + * \class LiveRuntime + * \brief Collects properties to be used for an enhanced live runtime. + * \group qmllive + * + * This runtime is used in an live enhanced qml project to be able to access more + * advanced features. Currently it does nothing + */ + +/*! + * Standard constructor using \a parent as parent + */ +LiveRuntime::LiveRuntime(QObject *parent) : + QObject(parent) +{ +} + +void LiveRuntime::setScreenHeight(qreal arg) +{ + if (m_screenHeight != arg) { + m_screenHeight = arg; + emit screenHeightChanged(arg); + } +} + +qreal LiveRuntime::screenWidth() const +{ + return m_screenWidth; +} + +qreal LiveRuntime::screenHeight() const +{ + return m_screenHeight; +} + +void LiveRuntime::setScreenWidth(qreal arg) +{ + if (m_screenWidth != arg) { + m_screenWidth = arg; + emit screenWidthChanged(arg); + } +} diff --git a/src/liveruntime.h b/src/liveruntime.h new file mode 100644 index 0000000..5c2b5a8 --- /dev/null +++ b/src/liveruntime.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> +#include <QtGui> + +class LiveRuntime : public QObject +{ + Q_OBJECT + + Q_PROPERTY(qreal screenWidth READ screenWidth WRITE setScreenWidth NOTIFY screenWidthChanged) + Q_PROPERTY(qreal screenHeight READ screenHeight WRITE setScreenHeight NOTIFY screenHeightChanged) + + +public: + explicit LiveRuntime(QObject *parent = 0); + qreal screenWidth() const; + qreal screenHeight() const; + +public slots: + void setScreenWidth(qreal arg); + void setScreenHeight(qreal arg); + +signals: + void screenWidthChanged(qreal arg); + void screenHeightChanged(qreal arg); + +private: + qreal m_screenWidth; + qreal m_screenHeight; +}; + diff --git a/src/logger.cpp b/src/logger.cpp new file mode 100644 index 0000000..a12b762 --- /dev/null +++ b/src/logger.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "logger.h" +#include "stdio.h" + +Logger *Logger::s_instance = 0; +bool Logger::s_ignoreMesssages = false; +QMutex Logger::m_mutex; + +/*! + * \class Logger + * \brief Installs a qt messageHandler and receives all log messages + * \group qmllive + * + * The intention is to use this class if you want to display the log into widget + * or you want to preproccess the log messages itself before displaying it + * + * \sa RemoteLogger + */ + +/*! + * Standard constructor using \a parent as parent + */ +Logger::Logger(QObject *parent) : + QObject(parent) +{ + if (s_instance) { + qFatal("Cannot create more than one Logger"); + } + s_instance = this; + + qInstallMessageHandler(messageHandler); +} + +/*! + * Standard destructor + */ +Logger::~Logger() +{ + qInstallMessageHandler(0); +} + +/*! + * When \a ignoreMessages set to true, the Logger ignores all incoming log messages + */ +void Logger::setIgnoreMessages(bool ignoreMessages) +{ + QMutexLocker l(&m_mutex); + s_ignoreMesssages = ignoreMessages; +} + +void Logger::messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) +{ + if (!s_instance) { + printf("No Logger instance for log message:\n %s\n", msg.toLatin1().constData()); + abort(); + } + + { + QMutexLocker l(&m_mutex); + if (s_ignoreMesssages) + return; + } + + emit s_instance->message(type, msg); + + // and output to stdout + QByteArray localMsg = msg.toLocal8Bit(); + switch (type) { + case QtDebugMsg: + fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); + break; + case QtWarningMsg: + fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); + break; + case QtCriticalMsg: + fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); + break; + case QtFatalMsg: + fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); + } +} + +/*! + * \fn void Logger::message(int type, const QString &msg) + * Emitted for every incoming log message + * \a type describes the type of the log message (QtMsgType). + * \a msg is the debug message + * This signal will not be emitted when ignoreMessages set to true + * \sa setIgnoreMessages() + */ diff --git a/src/logger.h b/src/logger.h new file mode 100644 index 0000000..a6f3ff8 --- /dev/null +++ b/src/logger.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QObject> +#include <QMutex> +#include <QUrl> + +class Logger : public QObject +{ + Q_OBJECT +public: + explicit Logger(QObject *parent = 0); + virtual ~Logger(); + +public Q_SLOTS: + static void setIgnoreMessages(bool ignoreMessages); + +Q_SIGNALS: + void message(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1); + +private: + static void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg); + + static Logger *s_instance; + static bool s_ignoreMesssages; + + static QMutex m_mutex; +}; diff --git a/src/logreceiver.cpp b/src/logreceiver.cpp new file mode 100644 index 0000000..5ecd123 --- /dev/null +++ b/src/logreceiver.cpp @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include <QUdpSocket> +#include <QStringList> +#include <QUrl> +#include "logreceiver.h" + +/*! + * \class LogReceiver + * \brief Connects to a port and waits for log messages sent via udp + * \group qmllive + * + * \sa Logger, RemoteLogger + */ + +/*! + * Standard constructor using \a parent as parent + */ +LogReceiver::LogReceiver(QObject *parent) : + QObject(parent), + m_socket(new QUdpSocket(this)) +{ + setPort(45454); + connect(m_socket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams())); +} + +/*! + * Sets the \a port on which we wait for incoming logs + */ +void LogReceiver::setPort(int port) +{ + m_port = port; +} + +void LogReceiver::setAddress(const QString &address) +{ + m_address = QHostAddress(address); +} + +void LogReceiver::connectToServer() +{ + m_socket->disconnectFromHost(); + m_socket->bind(m_address, m_port, QUdpSocket::ShareAddress); +} + +/*! + * The port on which we wait for incoming logs + */ +int LogReceiver::port() const +{ + return m_port; +} + +QString LogReceiver::address() const +{ + return m_address.toString(); +} + +void LogReceiver::processPendingDatagrams() +{ + while (m_socket->hasPendingDatagrams()) { + QByteArray datagram; + datagram.resize(m_socket->pendingDatagramSize()); + m_socket->readDatagram(datagram.data(), datagram.size()); + + QStringList data = QString::fromUtf8(datagram).split("%%%"); + if (data.count() != 5) { + qWarning("Invalid Log package received"); + return; + } + + emit message(data.at(0).toInt(), data.at(1), QUrl(data.at(2)) ,data.at(3).toInt(), data.at(4).toInt()); + } +} diff --git a/src/logreceiver.h b/src/logreceiver.h new file mode 100644 index 0000000..4f2a8fc --- /dev/null +++ b/src/logreceiver.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QObject> +#include <QUrl> +#include <QHostAddress> + +class QUdpSocket; +class LogReceiver : public QObject +{ + Q_OBJECT +public: + explicit LogReceiver(QObject *parent = 0); + + int port() const; + QString address() const; + +public Q_SLOTS: + void setPort(int port); + void setAddress(const QString& address); + void connectToServer(); + +Q_SIGNALS: + void message(int type, const QString &msg, const QUrl &url, int line, int column); + +private Q_SLOTS: + void processPendingDatagrams(); + +private: + QUdpSocket* m_socket; + QHostAddress m_address; + int m_port; +}; diff --git a/src/mainpage.dox b/src/mainpage.dox new file mode 100644 index 0000000..447b0a9 --- /dev/null +++ b/src/mainpage.dox @@ -0,0 +1,16 @@ +/************************************************************************************************ + * Copyright (c) 2012 Pelagicore AG. All rights reserved. + * + * This software, including documentation, is protected by copyright controlled by Pelagicore AG. + * All rights reserved. Copying, including reproducing, storing, adapting or translating, any or + * all of this material requires prior written consent of Pelagicore AG Corporation. This material + * also contains confidential information which may not be disclosed to others without the prior + * written consent of Pelagicore AG. + ************************************************************************************************/ + +/*! +\mainpage QmlLive Documentation + +Welcome to QmlLive. +*/ + diff --git a/src/previewGenerator/main.cpp b/src/previewGenerator/main.cpp new file mode 100644 index 0000000..ff3282d --- /dev/null +++ b/src/previewGenerator/main.cpp @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include <QApplication> +#include <QQuickView> +#include <QQmlEngine> +#include <QElapsedTimer> +#include <QDir> +#include <QBuffer> +#include <QLocalServer> +#include <QLocalSocket> +#include <QDebug> + +#include <stdio.h> + +void handlePreview(QLocalSocket *socket); + +class PreviewServer : public QObject +{ + Q_OBJECT +public: + PreviewServer() + : m_server(new QLocalServer()) + { + connect(m_server, SIGNAL(newConnection()), this, SLOT(onNewConnection())); + } + + bool listen() + { + return m_server->listen("QmlLivePreviewGenerator"); + } + + QString serverName() const + { + return m_server->serverName(); + } + +protected slots: + void onNewConnection() + { + while (m_server->hasPendingConnections()) { + QLocalSocket *socket = m_server->nextPendingConnection(); + + handlePreview(socket); + + delete socket; + } + } +private: + QLocalServer *m_server; +}; + + +FILE *dbgf = 0; + +int main (int argc, char** argv) +{ + QApplication app(argc, argv); + + if (app.arguments().count() != 2 || + (app.arguments().at(1) != "QmlLiveBench") ) + qFatal("This application is managed by QmlLive and is not supposed to be manually started"); + + PreviewServer preview; + if (!preview.listen()) { + qFatal("Failed to listen to local socket \"QmlLivePreviewGenerator\""); + } + + printf("ready#%s\n", preview.serverName().toUtf8().toHex().constData()); + fflush(stdout); + + //dbgf = fopen("C:\\Qt\\pg.log", "w"); + return app.exec(); +} + +void handlePreview(QLocalSocket *socket) +{ + if (dbgf) { fprintf(dbgf, "PG: waiting on input\n"); fflush(dbgf); } + + socket->waitForReadyRead(); + + QDataStream ds (socket); + QSize expectedSize; + QString path; + + ds >> expectedSize >> path; + + if (dbgf) { fprintf(dbgf, "PG: received [%dx%d] %s\n", expectedSize.width(), expectedSize.height(), qPrintable(path)); fflush(dbgf); } + + //QML Import paths and plugin paths will be set by environment variables + QQuickView *view = new QQuickView(); + view->setFlags(Qt::ToolTip | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint | + Qt::CustomizeWindowHint | Qt::WindowDoesNotAcceptFocus); // | Qt::WindowStaysOnBottomHint); + view->setPosition(-9999999, -9999999); + view->setSource(QUrl::fromLocalFile(path)); + + if (view->errors().isEmpty()) { + view->show(); + + //Wait until the Window is exposed; + int timeout = 3000; + QElapsedTimer timer; + timer.start(); + while (!view->isExposed()) { + int remaining = timeout - int(timer.elapsed()); + if (remaining <= 0) + break; + QCoreApplication::processEvents(QEventLoop::AllEvents, remaining); + //Garbage collection (Delivers all DeferredDeleteEvents which are in the pipe) + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + } + + if (view->width() <= 0 || view->height() <= 0) { + view->setWidth(500); + view->setHeight(500); + } + + if (view->rootObject()) { + QImage img = view->grabWindow(); + if (!img.isNull()) { + img = img.scaled(expectedSize, Qt::KeepAspectRatio); + img.save(socket, "PNG"); + + if (dbgf) { fprintf(dbgf, "PG: sending image\n"); fflush(dbgf); } + } + } + } + delete view; + + socket->write("\nEND"); + socket->flush(); + + if (dbgf) { fprintf(dbgf, "PG: sent END and flushed\n"); fflush(dbgf); } +} + + +#include "main.moc" diff --git a/src/previewGenerator/previewGenerator.pro b/src/previewGenerator/previewGenerator.pro new file mode 100644 index 0000000..7afd257 --- /dev/null +++ b/src/previewGenerator/previewGenerator.pro @@ -0,0 +1,13 @@ +TEMPLATE = app +TARGET = previewGenerator +DESTDIR = ../../bin + +osx: { + CONFIG -= app_bundle + DESTDIR = ../../bin/qmllivebench.app/Contents/MacOS/ +} + +QT = gui core quick widgets + +SOURCES += \ + main.cpp diff --git a/src/qmlhelper.cpp b/src/qmlhelper.cpp new file mode 100644 index 0000000..b47dbd3 --- /dev/null +++ b/src/qmlhelper.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "qmlhelper.h" + + +/*! + * \class QmlHelper + * \brief Provides a set of helper functions to setup your qml viewer + * \group qmllive + */ + +/*! + * \brief Standard constructor using \a parent as parent + */ +QmlHelper::QmlHelper(QObject *parent) : + QObject(parent) +{ +} + +/*! + * Loads dummy data from a "dummydata" folder in the workspace folder + * \a view defines the View where you want to export the dummy data to + * The "dummydata" will be searched in the "dummydata" sub directory of \a workspace + */ +void QmlHelper::loadDummyData(QQuickView *view, const QString &workspace) +{ + Q_ASSERT(view); + QDir dir(workspace + "/dummydata", "*.qml"); + foreach (QString entry, dir.entryList()) { + + QQmlComponent comp(view->engine(), dir.filePath(entry)); + QObject* obj = comp.create(); + + if (comp.isError()) { + foreach (const QQmlError error, comp.errors()) { + qWarning() << error; + } + } + if (obj) { + qWarning() << "loaded dummy data: " << dir.filePath(entry); + entry.chop(4); + view->rootContext()->setContextProperty(entry, obj); + obj->setParent(view); + } + } +} + +/*! + * \fn void QmlHelper::addImportPath(QQuickView *view, const QString &path) + * Adds an import path \a path to your qml viewer \a view + */ +void QmlHelper::addImportPath(QQuickView *view, const QString &path) +{ + Q_ASSERT(view); + view->engine()->addImportPath(path); +} + + + + diff --git a/src/qmlhelper.h b/src/qmlhelper.h new file mode 100644 index 0000000..7c5cb05 --- /dev/null +++ b/src/qmlhelper.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> +#include <QtQml> +#include <QtQuick> + +class QmlHelper : public QObject +{ + Q_OBJECT +public: + explicit QmlHelper(QObject *parent = 0); + + static void loadDummyData(QQuickView* view, const QString& workspace); + static void addImportPath(QQuickView* view, const QString& path); + +Q_SIGNALS: + +public Q_SLOTS: + +}; diff --git a/src/remotelogger.cpp b/src/remotelogger.cpp new file mode 100644 index 0000000..f2f2899 --- /dev/null +++ b/src/remotelogger.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include <QUdpSocket> +#include "remotelogger.h" + +/*! + * \class RemoteLogger + * \brief Installs a qt messageHandler and sends the logs over udp + * \group qmllive + * + * \sa Logger, LogReceiver + */ + +/*! + * Standard constructor using \a parent as parent + */ +RemoteLogger::RemoteLogger(QObject *parent) : + Logger(parent) , + m_socket(new QUdpSocket(this)) , + m_port(45454) +{ + connect(this, SIGNAL(message(int,QString)), this, SLOT(broadcast(int,QString))); +} + +/*! + * Sets the \a address where the log messages will be sent to + * \sa setPort() + */ +void RemoteLogger::setHostAddress(const QHostAddress &address) +{ + m_host = address; +} + +/*! + * Sets the \a port where the log messages will be sent to + * \sa setHostAddress() + */ +void RemoteLogger::setPort(int port) +{ + m_port = port; +} + +void RemoteLogger::broadcast(int type, const QString &msg, const QUrl &url, int line, int column) +{ + QByteArray datagram; + QStringList data; + data << QString::number(type) << msg << url.toString() << QString::number(line) << QString::number(column); + + datagram = data.join("%%%").toUtf8(); + m_socket->writeDatagram(datagram.data(), datagram.size(), + m_host, m_port); +} + +void RemoteLogger::appendToLog(const QList<QQmlError> &errors) +{ + foreach (const QQmlError &err, errors) { + if (!err.isValid()) + continue; + + QtMsgType type = QtDebugMsg; + + if (err.description().contains(QString::fromLatin1("error"), Qt::CaseInsensitive) || + err.description().contains(QString::fromLatin1("is not installed"), Qt::CaseInsensitive) || + err.description().contains(QString::fromLatin1("is not a type"), Qt::CaseInsensitive)) + type = QtCriticalMsg; + else if (err.description().contains(QString::fromLatin1("warning"), Qt::CaseInsensitive)) + type = QtWarningMsg; + + broadcast(type, err.description(), err.url(), err.line(), err.column()); + } +} diff --git a/src/remotelogger.h b/src/remotelogger.h new file mode 100644 index 0000000..f41e106 --- /dev/null +++ b/src/remotelogger.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include "logger.h" +#include <QHostAddress> +#include <QtQuick> + +class QUdpSocket; +class RemoteLogger : public Logger +{ + Q_OBJECT +public: + explicit RemoteLogger(QObject *parent = 0); + +public Q_SLOTS: + void setHostAddress(const QHostAddress &address); + void setPort(int port); + void appendToLog(const QList<QQmlError> &errors); + +private Q_SLOTS: + void broadcast(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1); + +private: + QUdpSocket* m_socket; + int m_port; + QHostAddress m_host; +}; diff --git a/src/remotepublisher.cpp b/src/remotepublisher.cpp new file mode 100644 index 0000000..5ee343b --- /dev/null +++ b/src/remotepublisher.cpp @@ -0,0 +1,243 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "remotepublisher.h" +#include "ipc/ipcclient.h" +#include "livehubengine.h" + +#ifdef QMLLIVE_DEBUG +#define DEBUG qDebug() +#else +#define DEBUG if (0) qDebug() +#endif +/*! + * \class RemotePublisher + * \brief Publishes hub changes to a remote node + * \group qmllive + * + * To see the progress which commands were really sent successfully to to the server + * you have to connect the signals from the LiveHubEngine yourself and monitor the QUuids you + * got and wait for sendingError() or sentSuccessfully() signals + */ + +/*! + * Standard Constructor using \a parent as parent + */ +RemotePublisher::RemotePublisher(QObject *parent) + : QObject(parent) + , m_ipc(new IpcClient(this)) + , m_hub(0) +{ + connect(m_ipc, SIGNAL(sentSuccessfully(QUuid)), this, SIGNAL(sentSuccessfully(QUuid))); + connect(m_ipc, SIGNAL(sendingError(QUuid,QAbstractSocket::SocketError)), + this, SIGNAL(sendingError(QUuid,QAbstractSocket::SocketError))); + connect(m_ipc, SIGNAL(connectionError(QAbstractSocket::SocketError)), + this, SIGNAL(connectionError(QAbstractSocket::SocketError))); + connect(m_ipc, SIGNAL(connected()), this, SIGNAL(connected())); + connect(m_ipc, SIGNAL(disconnected()), this, SIGNAL(disconnected())); + + connect(m_ipc, SIGNAL(received(QString,QByteArray)), this, SLOT(handleCall(QString,QByteArray))); + + connect(m_ipc, SIGNAL(sentSuccessfully(QUuid)), this, SLOT(onSentSuccessfully(QUuid))); + connect(m_ipc, SIGNAL(sendingError(QUuid,QAbstractSocket::SocketError)), + this, SLOT(onSendingError(QUuid,QAbstractSocket::SocketError))); +} + +QAbstractSocket::SocketState RemotePublisher::state() const +{ + return m_ipc->state(); +} + +/*! + * Register the \a hub to be used with this publisher + */ +void RemotePublisher::registerHub(LiveHubEngine *hub) +{ + if (m_hub) { + disconnect(m_hub); + } + m_hub = hub; + connect(hub, SIGNAL(activateDocument(QString)), this, SLOT(activateDocument(QString))); + connect(hub, SIGNAL(fileChanged(QString)), this, SLOT(sendDocument(QString))); +} + +/*! + * Sets the current workspace to \a path. Documents location will be adjusted based on + * this workspace path. + */ +void RemotePublisher::setWorkspace(const QString &path) +{ + m_workspace = QDir(path); +} + +/*! + * Set Ipc destination to use \a hostName and \a port + * \sa IpcClient::connectToServer() + */ +void RemotePublisher::connectToServer(const QString &hostName, int port) +{ + m_ipc->connectToServer(hostName, port); +} + +QString RemotePublisher::errorToString(QAbstractSocket::SocketError error) +{ + return m_ipc->errorToString(error); +} + +void RemotePublisher::disconnectFromServer() +{ + m_ipc->disconnectFromServer(); +} + +/*! + * Send "activateDocument(QString)" to ipc-server on activate document. + * \a document defines the Document which should be activated + */ +QUuid RemotePublisher::activateDocument(const QString &document) +{ + DEBUG << "RemotePublisher::activateDocument" << document; + QByteArray bytes; + QDataStream out(&bytes, QIODevice::WriteOnly); + out << document; + return m_ipc->send("activateDocument(QString)", bytes); +} + +/*! + * Send "sendDocument(QString,QByteArray)" to ipc-server on send document. + * It sends \a document with content \a data + */ +QUuid RemotePublisher::sendDocument(const QString& document) +{ + DEBUG << "RemotePublisher::sendDocument" << document; + return sendWholeDocument(document); +} + +QUuid RemotePublisher::checkPin(const QString &pin) +{ + DEBUG << "RemotePublisher::checkPin" << pin; + QByteArray bytes; + QDataStream out(&bytes, QIODevice::WriteOnly); + out << pin; + return m_ipc->send("checkPin(QString)", bytes); +} + +QUuid RemotePublisher::setXOffset(int offset) +{ + QByteArray bytes; + QDataStream out(&bytes, QIODevice::WriteOnly); + out << offset; + return m_ipc->send("setXOffset(int)", bytes); +} + +QUuid RemotePublisher::setYOffset(int offset) +{ + QByteArray bytes; + QDataStream out(&bytes, QIODevice::WriteOnly); + out << offset; + return m_ipc->send("setYOffset(int)", bytes); +} + +QUuid RemotePublisher::setRotation(int rotation) +{ + QByteArray bytes; + QDataStream out(&bytes, QIODevice::WriteOnly); + out << rotation; + return m_ipc->send("setRotation(int)", bytes); +} + +QUuid RemotePublisher::sendWholeDocument(const QString& document) +{ + DEBUG << "RemotePublisher::sendWholeDocument" << document; + QFile file(document); + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "ERROR: can't open file: " << document; + return QUuid(); + } + QByteArray data = file.readAll(); + + QByteArray bytes; + QDataStream out(&bytes, QIODevice::WriteOnly); + out << m_workspace.relativeFilePath(document); + out << data; + return m_ipc->send("sendDocument(QString,QByteArray)", bytes); +} + +void RemotePublisher::onSentSuccessfully(const QUuid &uuid) +{ + QString path = m_packageHash.value(uuid); + m_packageHash.remove(uuid); + + QList<QUuid> keys = m_packageHash.keys(path); + if (keys.count() == 1) { + m_packageHash.remove(keys.at(0)); + emit sentSuccessfully(keys.at(0)); + } +} + +void RemotePublisher::onSendingError(const QUuid &uuid, QAbstractSocket::SocketError socketError) +{ + QString path = m_packageHash.value(uuid); + m_packageHash.remove(uuid); + + QList<QUuid> keys = m_packageHash.keys(path); + if (keys.count() == 1) { + m_packageHash.remove(keys.at(0)); + emit sendingError(keys.at(0), socketError); + } +} + + +void RemotePublisher::handleCall(const QString &method, const QByteArray &content) +{ + DEBUG << "RemotePublisher::handleIpcCall: " << method << content; + + if (method == "needsPinAuthentication()") { + qDebug() << "needsPinAuthentication"; + emit needsPinAuthentication(); + } else if (method == "pinOK(bool)") { + qDebug() << "pinOk" << content.toInt(); + emit pinOk(content.toInt()); + } else if (method == "qmlLog(QtMsgType, QString, QUrl, int, int)") { + int msgType; + QString description; + QUrl url; + int line = -1; + int column = -1; + + QDataStream in(content); + in >> msgType; + in >> description; + in >> url; + in >> line; + in >> column; + + emit remoteLog(msgType, description, url, line, column); + } +} diff --git a/src/remotepublisher.h b/src/remotepublisher.h new file mode 100644 index 0000000..2132787 --- /dev/null +++ b/src/remotepublisher.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> +#include <QAbstractSocket> + +class LiveHubEngine; +class IpcClient; + +class RemotePublisher : public QObject +{ + Q_OBJECT +public: + explicit RemotePublisher(QObject *parent = 0); + void connectToServer(const QString& hostName, int port); + QString errorToString(QAbstractSocket::SocketError error); + QAbstractSocket::SocketState state() const; + + void registerHub(LiveHubEngine *hub); +Q_SIGNALS: + void connected(); + void disconnected(); + void sentSuccessfully(const QUuid& uuid); + void sendingError(const QUuid& uuid, QAbstractSocket::SocketError socketError); + void connectionError(QAbstractSocket::SocketError error); + void needsPinAuthentication(); + void pinOk(bool ok); + void remoteLog(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1); + +public Q_SLOTS: + void setWorkspace(const QString &path); + void disconnectFromServer(); + QUuid activateDocument(const QString& document); + QUuid sendDocument(const QString& document); + QUuid checkPin(const QString& pin); + QUuid setXOffset(int offset); + QUuid setYOffset(int offset); + QUuid setRotation(int rotation); + +private Q_SLOTS: + void handleCall(const QString &method, const QByteArray &content); + QUuid sendWholeDocument(const QString &document); + + void onSentSuccessfully(const QUuid& uuid); + void onSendingError(const QUuid& uuid, QAbstractSocket::SocketError socketError); + +private: + IpcClient *m_ipc; + LiveHubEngine *m_hub; + QDir m_workspace; + + QHash<QUuid, QString> m_packageHash; +}; diff --git a/src/remotereceiver.cpp b/src/remotereceiver.cpp new file mode 100644 index 0000000..7bacb46 --- /dev/null +++ b/src/remotereceiver.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "remotereceiver.h" +#include "ipc/ipcserver.h" +#include "ipc/ipcclient.h" +#include "livenodeengine.h" + +#include <QTcpSocket> + +#ifdef QMLLIVE_DEBUG +#define DEBUG qDebug() +#else +#define DEBUG if (0) qDebug() +#endif + +RemoteReceiver::RemoteReceiver(QObject *parent) + : QObject(parent) + , m_server(new IpcServer(this)) + , m_node(0) + , m_connectionAcknowledged(false) + , m_socket(0) + , m_client(0) +{ + connect(m_server, SIGNAL(received(QString,QByteArray)), this, SLOT(handleCall(QString,QByteArray))); + connect(m_server, SIGNAL(clientConnected(QTcpSocket*)), this, SLOT(onClientConnected(QTcpSocket*))); + connect(m_server, SIGNAL(clientConnected(QHostAddress)), this, SIGNAL(clientConnected(QHostAddress))); + connect(m_server, SIGNAL(clientDisconnected(QHostAddress)), this, SIGNAL(clientDisconnected(QHostAddress))); +} + +void RemoteReceiver::listen(int port) +{ + m_server->listen(port); +} + +/*! + * Sets the current workspace to \a path. Documents location will be adjusted based on + * this workspace path. + */ +void RemoteReceiver::setWorkspace(const QString &path) +{ + m_workspace = QDir(path); +} + +QString RemoteReceiver::workspace() const +{ + return m_workspace.absolutePath(); +} + +void RemoteReceiver::setPin(const QString &pin) +{ + m_pin = pin; +} + +QString RemoteReceiver::pin() const +{ + return m_pin; +} + +void RemoteReceiver::setMaxConnections(int max) +{ + m_server->setMaxConnections(max); +} + +/*! + * Sets whether the workspace is writeable to \a on. Otherwise incoming write document requests will be ignored. + */ +void RemoteReceiver::setWorkspaceWriteable(bool on) +{ + m_workspaceWriteable = on; +} + + +void RemoteReceiver::handleCall(const QString &method, const QByteArray &content) +{ + DEBUG << "RemoteReceiver::handleIpcCall: " << method; + + if (method == "checkPin(QString)") { + QString pin; + QDataStream in(content); + in >> pin; + if (m_pin == pin && m_client) { + m_connectionAcknowledged = true; + emit pinOk(true); + m_client->send("pinOK(bool)", QByteArray::number(1)); + } else if (m_client) { + emit pinOk(false); + m_client->send("pinOK(bool)", QByteArray::number(0)); + } + } + + if (!m_connectionAcknowledged) { + qWarning() << "Connecting without Pin Authentication is not allowed"; + return; + } + + if (method == "setXOffset(int)") { + int offset; + QDataStream in(content); + in >> offset; + emit xOffsetChanged(offset); + } else if (method == "setYOffset(int)") { + int offset; + QDataStream in(content); + in >> offset; + emit yOffsetChanged(offset); + } else if (method == "setRotation(int)") { + int rotation; + QDataStream in(content); + in >> rotation; + emit rotationChanged(rotation); + } else if (method == "sendDocument(QString,QByteArray)") { + QString document; + QByteArray data; + QDataStream in(content); + in >> document; + in >> data; + writeDocument(document, data); + } else if (method == "activateDocument(QString)") { + QString document; + QDataStream in(content); + in >> document; + qDebug() << "\tactivate document: " << document; + emit activateDocument(document); + } else if (method == "ping()") { + if (m_client) + m_client->send("pong()", QByteArray()); + } +} + + +void RemoteReceiver::registerNode(LiveNodeEngine *node) +{ + if (m_node) { disconnect(m_node); } + m_node = node; + connect(this, SIGNAL(activateDocument(QString)), m_node, SLOT(setActiveDocument(QString))); +} + +void RemoteReceiver::writeDocument(const QString &document, const QByteArray &content) +{ + if (!m_workspaceWriteable) { return; } + QString filePath = m_workspace.absoluteFilePath(document); + QString dirPath = QFileInfo(filePath).absoluteDir().absolutePath(); + m_workspace.mkpath(dirPath); + QFile file(filePath); + if (!file.open(QIODevice::WriteOnly)) { + qWarning() << "Unable to save file: " << file.errorString(); + return; + } + file.write(content); + file.close(); + + if (m_node) + m_node->delayReload(); +} + +void RemoteReceiver::onClientConnected(QTcpSocket *socket) +{ + if (m_client) + delete m_client; + + m_client = new IpcClient(socket); + + m_socket = socket; + + if (!m_pin.isEmpty()) { + m_client->send("needsPinAuthentication()", QByteArray()); + m_connectionAcknowledged = false; + } else { + m_connectionAcknowledged = true; + } +} + +void RemoteReceiver::appendToLog(const QList<QQmlError> &errors) +{ + foreach (const QQmlError &err, errors) { + if (!err.isValid()) + continue; + + QtMsgType type = QtDebugMsg; + + if (err.description().contains(QString::fromLatin1("error"), Qt::CaseInsensitive) || + err.description().contains(QString::fromLatin1("is not installed"), Qt::CaseInsensitive) || + err.description().contains(QString::fromLatin1("is not a type"), Qt::CaseInsensitive)) + type = QtCriticalMsg; + else if (err.description().contains(QString::fromLatin1("warning"), Qt::CaseInsensitive)) + type = QtWarningMsg; + + QByteArray bytes; + QDataStream out(&bytes, QIODevice::WriteOnly); + out << type; + out << err.description(); + out << err.url(); + out << err.line(); + out << err.column(); + + m_client->send("qmlLog(QtMsgType, QString, QUrl, int, int)", bytes); + } +} diff --git a/src/remotereceiver.h b/src/remotereceiver.h new file mode 100644 index 0000000..7e7b16e --- /dev/null +++ b/src/remotereceiver.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> +#include <QHostAddress> + +#include <QQmlError> + +class QTcpSocket; +class LiveNodeEngine; +class IpcServer; +class IpcClient; + +class RemoteReceiver : public QObject +{ + Q_OBJECT +public: + explicit RemoteReceiver(QObject *parent = 0); + void listen(int port); + void registerNode(LiveNodeEngine *node); + void setWorkspaceWriteable(bool on); + void setWorkspace(const QString &path); + QString workspace() const; + void setPin(const QString& pin); + QString pin() const; + + void setMaxConnections(int max); +Q_SIGNALS: + void activateDocument(const QString& document); + void reload(); + void clientConnected(const QHostAddress& address); + void clientDisconnected(const QHostAddress& address); + void pinOk(bool ok); + void xOffsetChanged(int offset); + void yOffsetChanged(int offset); + void rotationChanged(int rotation); + +private Q_SLOTS: + void handleCall(const QString& method, const QByteArray& content); + void writeDocument(const QString& document, const QByteArray& content); + + void appendToLog(const QList<QQmlError> &errors); + + void onClientConnected(QTcpSocket *socket); +private: + IpcServer *m_server; + LiveNodeEngine *m_node; + + QDir m_workspace; + bool m_workspaceWriteable; + + QString m_pin; + bool m_connectionAcknowledged; + + QTcpSocket* m_socket; + IpcClient* m_client; +}; + diff --git a/src/runtime/main.cpp b/src/runtime/main.cpp new file mode 100644 index 0000000..2c2a4f1 --- /dev/null +++ b/src/runtime/main.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include <QtGui> +#include <QCryptographicHash> +#include <QtQuick> +#include <QtWidgets> + +#include "livenodeengine.h" +#include "remotereceiver.h" +#include "logger.h" +#include "qmlhelper.h" + + +struct Options +{ + Options() + : ipcPort(10234) + , allowUpdates(true) + , fullscreen(false) + , transparent(false) + , frameless(false) + , stayontop(false) + {} + int ipcPort; + bool allowUpdates; + QString activeDocument; + QString workspace; + QString pluginPath; + QStringList importPaths; + bool fullscreen; + bool transparent; + bool frameless; + bool stayontop; +}; + +static Options options; + +static void usage() +{ + qWarning("Usage qmlliveruntime [options] <workspace>"); + qWarning(" "); + qWarning(" options:"); + qWarning(" -ipcport <port> ....................the port the ipc shall listen on"); + qWarning(" -no-file-updates ...................do not write to files on changes"); + qWarning(" -pluginpath ........................path to qmllive plugins"); + qWarning(" -importpath ........................path to the qml import path"); + qWarning(" -fullscreen ........................shows in fullscreen mode"); + qWarning(" -transparent .......................Make the window transparent"); + qWarning(" -frameless .........................run with no window frame"); + qWarning(" -stayontop .........................keep viewer window on top"); + qWarning(" "); + exit(1); +} + +static void parseArguments(const QStringList& arguments) +{ + for (int i = 1; i < arguments.count(); ++i) { + bool lastArg = (i == arguments.count() - 1); + QString arg = arguments.at(i); + if (arg == QLatin1String("-ipcport")) { + if (lastArg || arguments.at(++i).startsWith(QLatin1Char('-'))) usage(); + options.ipcPort = arguments.at(i).toInt(); + } else if (arg == QLatin1String("-pluginpath")) { + if (lastArg || arguments.at(++i).startsWith(QLatin1Char('-'))) usage(); + options.pluginPath = arguments.at(i); + } else if (arg == QLatin1String("-importpath")) { + if (lastArg || arguments.at(++i).startsWith(QLatin1Char('-'))) usage(); + options.importPaths.append(QDir(arguments.at(i)).absolutePath()); + continue; + } else if (arg == QLatin1String("-no-file-updates")) { + options.allowUpdates = false; + } else if (arg == QLatin1String("-fullscreen")) { + options.fullscreen = true; + } else if (arg == QLatin1String("-transparent")) { + options.transparent = true; + } else if (arg == QLatin1String("-frameless")) { + options.frameless = true; + } else if (arg == QLatin1String("-stayontop")) { + options.stayontop = true; + } else if (!arg.startsWith(QLatin1Char('-'))) { + options.workspace = arg; + } else if (true || arg == QLatin1String("-help")) { + usage(); + } + } +} + +class RuntimeLiveNodeEngine : public LiveNodeEngine { + + virtual QQuickView* initView() + { + QQuickView* view = new QQuickView(); + if (options.transparent) { + QSurfaceFormat surfaceFormat; + surfaceFormat.setAlphaBufferSize(8); + view->setFormat(surfaceFormat); + view->setClearBeforeRendering(true); + view->setColor(QColor(Qt::transparent)); + } + + if (options.stayontop) { + view->setFlags(view->flags() | Qt::X11BypassWindowManagerHint); + view->setFlags(view->flags() | Qt::WindowStaysOnTopHint); + } + + if (options.frameless) + view->setFlags(view->flags() | Qt::FramelessWindowHint); + + if (options.fullscreen) + view->setWindowState(Qt::WindowFullScreen); + + return view; + } +}; + +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + app.setApplicationName("QmlLiveRuntime"); + app.setOrganizationDomain("pelagicore.com"); + app.setOrganizationName("Pelagicore"); + parseArguments(app.arguments()); + + QQuickView view; + + QStringList defaultImports = view.engine()->importPathList(); + + RuntimeLiveNodeEngine engine; + engine.setUpdateMode(LiveNodeEngine::RecreateView); + engine.setWorkspace(options.workspace); + engine.setPluginPath(options.pluginPath); + engine.setImportPaths(options.importPaths + defaultImports); + engine.loadDocument(QUrl("qrc:/qml/qmlsplash/splash-qt5.qml")); + RemoteReceiver receiver; + receiver.listen(options.ipcPort); + receiver.setWorkspace(options.workspace); + receiver.setWorkspaceWriteable(options.allowUpdates); + receiver.registerNode(&engine); + + engine.connect(&engine, SIGNAL(logErrors(QList<QQmlError>)), &receiver, SLOT(appendToLog(QList<QQmlError>))); + + receiver.connect(&receiver, SIGNAL(xOffsetChanged(int)), &engine, SLOT(setXOffset(int))); + receiver.connect(&receiver, SIGNAL(yOffsetChanged(int)), &engine, SLOT(setYOffset(int))); + receiver.connect(&receiver, SIGNAL(rotationChanged(int)), &engine, SLOT(setRotation(int))); + + QMap<QString, QString> extraSyslog; + extraSyslog.insert("LOCATION", QString("qmllive://${HOST}:%1").arg(options.ipcPort)); + + int ret = app.exec(); + + return ret; +} diff --git a/src/runtime/qml.qrc b/src/runtime/qml.qrc new file mode 100644 index 0000000..f47865a --- /dev/null +++ b/src/runtime/qml.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/qml"> + <file>qmlsplash/pelagicore-symbol-white-rgb.png</file> + <file>qmlsplash/splash-qt5.qml</file> + </qresource> +</RCC> diff --git a/src/runtime/qmlsplash/pelagicore-symbol-white-rgb.png b/src/runtime/qmlsplash/pelagicore-symbol-white-rgb.png Binary files differnew file mode 100644 index 0000000..09e7dce --- /dev/null +++ b/src/runtime/qmlsplash/pelagicore-symbol-white-rgb.png diff --git a/src/runtime/qmlsplash/splash-qt4.qml b/src/runtime/qmlsplash/splash-qt4.qml new file mode 100644 index 0000000..799928e --- /dev/null +++ b/src/runtime/qmlsplash/splash-qt4.qml @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +import QtQuick 1.1 + +Rectangle { + id: root + width: 1024 + height: 768 + color: "#FF6600" + + Image { + id: logo + source: "pelagicore-symbol-white-rgb.png" + x: 50 + anchors.top: parent.top + anchors.topMargin: 100 + anchors.bottom: parent.bottom + anchors.bottomMargin: 250 + + fillMode: Image.PreserveAspectFit + } + + Text { + id: mantraText + + text: "Open Source Infotainment\n Enabling Great Design" + + font.pixelSize: 60 + color: "white" + lineHeight: 1.2 + + y: logo.y + anchors.left: logo.right + anchors.leftMargin: 25 + + } + + Text { + id: qmllivetext + text: "QmlLive" + + font.pixelSize: 70 + color: "white" + + x: mantraText.x + anchors.top: mantraText.bottom + anchors.margins: 200 + } + Text { + id: pleaseConnectText + text: "Please connect with QmlLiveRemote" + + font.pixelSize: 40 + color: "white" + SequentialAnimation { + running: true + loops: Animation.Infinite + ColorAnimation { target: pleaseConnectText; property: "color"; from: "white"; to: root.color; duration: 2000;} + ColorAnimation { target: pleaseConnectText; property: "color"; from: root.color; to: "white"; duration: 2000;} + } + + x: mantraText.x + anchors.top: qmllivetext.bottom + anchors.margins: 20 + } +} diff --git a/src/runtime/qmlsplash/splash-qt5.qml b/src/runtime/qmlsplash/splash-qt5.qml new file mode 100644 index 0000000..6743343 --- /dev/null +++ b/src/runtime/qmlsplash/splash-qt5.qml @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: root + width: 1024 + height: 768 + color: "#FF6600" + + Image { + id: logo + source: "pelagicore-symbol-white-rgb.png" + x: 50 + anchors.top: parent.top + anchors.topMargin: 100 + anchors.bottom: parent.bottom + anchors.bottomMargin: 250 + + fillMode: Image.PreserveAspectFit + } + + Text { + id: mantraText + + text: "Open Source Infotainment\n Enabling Great Design" + + font.pixelSize: 60 + color: "white" + lineHeight: 1.2 + + y: logo.y + anchors.left: logo.right + anchors.leftMargin: 25 + + } + + Text { + id: qmllivetext + text: "QmlLive" + + font.pixelSize: 70 + color: "white" + + x: mantraText.x + anchors.top: mantraText.bottom + anchors.margins: 200 + } + Text { + id: pleaseConnectText + text: "Please connect with QmlLiveRemote" + + font.pixelSize: 40 + color: "white" + SequentialAnimation { + running: true + loops: Animation.Infinite + ColorAnimation { target: pleaseConnectText; property: "color"; from: "white"; to: root.color; duration: 2000;} + ColorAnimation { target: pleaseConnectText; property: "color"; from: root.color; to: "white"; duration: 2000;} + } + + + x: mantraText.x + anchors.top: qmllivetext.bottom + anchors.margins: 20 + } +} diff --git a/src/runtime/runtime.pro b/src/runtime/runtime.pro new file mode 100644 index 0000000..73dd6d7 --- /dev/null +++ b/src/runtime/runtime.pro @@ -0,0 +1,19 @@ +TARGET = qmlliveruntime +DESTDIR = ../../bin + +QT *= widgets quick +osx: CONFIG -= app_bundle + +SOURCES += main.cpp + +win32: RC_FILE = ../../icons/appicon.rc + +include(../widgets/widgets.pri) +include(../src.pri) + +RESOURCES += \ + qml.qrc + + + + diff --git a/src/src.pri b/src/src.pri new file mode 100644 index 0000000..326f705 --- /dev/null +++ b/src/src.pri @@ -0,0 +1,54 @@ +!greaterThan(QT_MAJOR_VERSION, 4):error("You need at least Qt5 to build this application") + +QT *= quick quick-private qml-private network + +INCLUDEPATH += $${PWD} +DEFINES += NO_LIBRSYNC + +SOURCES += \ + $$PWD/watcher.cpp \ + $$PWD/livehubengine.cpp \ + $$PWD/livenodeengine.cpp \ + $$PWD/qmlhelper.cpp \ + $$PWD/liveruntime.cpp \ + $$PWD/remotepublisher.cpp \ + $$PWD/remotereceiver.cpp \ + $$PWD/imageadapter.cpp \ + $$PWD/contentpluginfactory.cpp \ + $$PWD/logger.cpp \ + $$PWD/remotelogger.cpp \ + $$PWD/logreceiver.cpp \ + $$PWD/fontadapter.cpp + +HEADERS += \ + $$PWD/watcher.h \ + $$PWD/livehubengine.h \ + $$PWD/livenodeengine.h \ + $$PWD/qmlhelper.h \ + $$PWD/liveruntime.h \ + $$PWD/remotepublisher.h \ + $$PWD/remotereceiver.h \ + $$PWD/contentadapterinterface.h \ + $$PWD/imageadapter.h \ + $$PWD/contentpluginfactory.h \ + $$PWD/logger.h \ + $$PWD/remotelogger.h \ + $$PWD/logreceiver.h \ + $$PWD/fontadapter.h + +OTHER_FILES += \ + $$PWD/livert/error_qt5.qml \ + $$PWD/livert/error_qt5_controls.qml \ + $$PWD/livert/imageviewer_qt5.qml \ + $$PWD/livert/imageviewer_qt5_controls.qml \ + $$PWD/livert/folderview_qt5.qml \ + $$PWD/livert/folderview_qt5_controls.qml \ + $$PWD/livert/fontviewer_qt5.qml \ + $$PWD/livert/fontviewer_qt5_controls.qml + +RESOURCES += \ + $$PWD/livert.qrc + +include(ipc/ipc.pri) + + diff --git a/src/src.pro b/src/src.pro new file mode 100644 index 0000000..96e3681 --- /dev/null +++ b/src/src.pro @@ -0,0 +1,9 @@ +TEMPLATE = subdirs +CONFIG += ordered + +SUBDIRS += \ + bench \ + previewGenerator \ + runtime \ + +include(src.pri) diff --git a/src/usage.dox b/src/usage.dox new file mode 100644 index 0000000..431e189 --- /dev/null +++ b/src/usage.dox @@ -0,0 +1,122 @@ +/*! +\page usage Usage + +The QmlLive system ws designed from the ground up to support your needs. It is structured in a modular fashion to be able to support various usage requirements. + +In the early phase of a project you normally want to use the `QmlLiveBench`, which has everything included in a typical desktop application. Later in the project you may want to test your UI code on a device. For this we have designed the `QmlLiveRuntime` in combination with the `QmlLiveRemote`. This combi pack offers you a default qml renderer to be run on the device and a small remote application on the desktop to control it. For the C++ developers we also offer the ability to just integrate the QmlLive system into your own custom runtime using our *QmlLiveNodeEngine* class with a few lines of code and then use the *QmlLiveRemote* to instrument it. + +Workbench +--------- + +The standard workbench is the all inclusve qml live tool. It allows you to select a workspace to watch over and provides a default qml runtime for the active selected qml document. + +![Workbench](images/workbench.png) + +You launch it by just executing the ``qmllivebench`` executable + + $(QMLIVEPROJECT)/bin/qmllivebench[.exe] + + +Creator Integration +------------------- + +You can integrate the QmlLiveBench into creator as an external tool. For this you need to open the Settings/Options dialog from QtCreator and open the `Environment` group. There you will find the ``External Tools`` tab. + +Under exectuble enter the path of your QmlLiveBench executable. + +![Creator](images/creator_tool.png) + +Now QmlLiveBench is availabe under the menu entry Tool->External->QmlLiveBench. To be able to easier launch QmlLiveBench you can also assign a shortcut to the tool. + +![Creator](images/creator_shortcut.png) + +Now when you press "Alt-F8" QmlLiveBench will be launched with the current project root folder open as workspace. + +![Creator](images/creator_result.png) + + + +Default Runtime +--------------- + +The default runtime is meant to be used with the QmlLiveRemote tool. It provides a default qml viewer and listens on a given port for ipc calls from the remote. As such it's ideal to start developing on a target device, when no extra c++ code is required. + +![Runtime](images/runtime.png) + +Calling the runtime + + $(QMLIVEPROJECT)/bin/qmlliveruntime[.exe] + +Usage of the runtime + + Usage qmlliveruntime [options] <workspace> + + options: + -ipcport <port> + -no-writes + + +Remote +------ + +The remote controls a runtime running on the same PC or on another device. On changes on the workspace is send the changes over to the runtime and reloads the current active document. + +![Remote](images/remote.png) + +QmlLiveRemote Execution + + $(QMLIVEPROJECT)/bin/qmlliveremote[.exe] + +Note: Is it possible to disable the publishing of source changes + + +QmlLiveRemote Usage + + Usage qmlliveremote [options] <workspace> + + options: + -activate <qml-document> ....... active document + -runtime <ip-address:port> ..... define remote runtime + -publishFirst .................. publish initially the workspace + -publishChanges ................ allow publishing workspace changes to remote + + +Custom Runtime +-------------- + +You can create your own custom runtime with the QmlLive features. This allows you to use your qml view setup with your additional c++ code together with the QmlLive system. + +For this you need to add `$(QMLLIVEPROJECT)/src/src.pri` to your project folder and use the `LiveNodeEngine` class to be able to receive workspace changes and active document updates. By default the IPC will listen on the port 10234. + +Here is a short example of a minimal custom runtime: + +\code{.cpp} +#include <QtGui> +#include <QtDeclarative> + +// use live node header +#include "livenodeengine.h" + +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + QDeclarativeView view; + + LiveNodeEngine node; + // let qml live instrument your view + node.setView(&view); + // where file updates should be stored relative to + node.setWorkspace("."); + // for local usage use the LocalPublisher + RemoteReceiver receiver; + receiver.registerNode(node); + // listen to ipc call from remote + receiver.listen(10234); + + view.setResizeMode(QDeclarativeView::SizeViewToRootObject); + view.show(); + return app.exec(); +} +\endcode + +*/ diff --git a/src/usage.qdoc b/src/usage.qdoc new file mode 100644 index 0000000..6cf8e38 --- /dev/null +++ b/src/usage.qdoc @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +/*! +\page usage.html + +The QmlLive system was designed from the ground up to support your needs. It is structured in a modular fashion to be able to support various usage requirements. + +In the early phase of a project you normally want to use the \bold{QmlLiveBench}, which has everything included in a typical desktop application. Later in the project you may want to test your UI code on a device. For this we have designed the \bold{QmlLiveRuntime} in combination with the \bold{QmlLiveRemote}. This combi pack offers you a default qml renderer to be run on the device and a small remote application on the desktop to control it. For the C++ developers we also offer the ability to just integrate the QmlLive system into your own custom runtime using our LiveNodeEngine class with a few lines of code and then use the \bold{QmlLiveRemote} to instrument it. + +\section1 Workbench + +The standard workbench is the all inclusve qml live tool. It allows you to select a workspace to watch over and provides a default qml runtime for the active selected qml document. + +\image workbench.png Workbench + +You launch it by just executing the \tt{qmllivebench} executable +\code +{$(QMLIVEPROJECT)/bin/qmllivebench[.exe] +\endcode + + +\section2 Creator Integration + +You can integrate the QmlLiveBench into creator as an external tool. For this you need to open the Settings/Options dialog from QtCreator and open the \bold{Environment} group. There you will find the \tt{External Tools} tab. + +Under exectuble enter the path of your QmlLiveBench executable. + +\image creator_tool.png Creator + +Now QmlLiveBench is availabe under the menu entry Tool->External->QmlLiveBench. To be able to easier launch QmlLiveBench you can also assign a shortcut to the tool. + +\image creator_shortcut.png Creator + +Now when you press "Alt-F8" QmlLiveBench will be launched with the current project root folder open as workspace. + +\image creator_result.png Creator + + + +\section2 Default Runtime + +The default runtime is meant to be used with the QmlLiveRemote tool. It provides a default qml viewer and listens on a given port for ipc calls from the remote. As such it's ideal to start developing on a target device, when no extra c++ code is required. + +\image runtime.png Runtime + +Calling the runtime + +\code +$(QMLIVEPROJECT)/bin/qmlliveruntime[.exe] +\endcode + +Usage of the runtime + +\code + Usage qmlliveruntime [options] <workspace> + + options: + -ipcport <port> + -no-writes +\endcode + + +\section1 Remote + +The remote controls a runtime running on the same PC or on another device. On changes on the workspace is send the changes over to the runtime and reloads the current active document. + +\image remote.png Remote + +QmlLiveRemote Execution + +\code + $(QMLIVEPROJECT)/bin/qmlliveremote[.exe] +\endcode + +Note: Is it possible to disable the publishing of source changes + + +QmlLiveRemote Usage + +\code + Usage qmlliveremote [options] <workspace> + + options: + -activate <qml-document> ....... active document + -runtime <ip-address:port> ..... define remote runtime + -publishFirst .................. publish initially the workspace + -publishChanges ................ allow publishing workspace changes to remote +\endcode + + +\section2 Custom Runtime + +You can create your own custom runtime with the QmlLive features. This allows you to use your qml view setup with your additional c++ code together with the QmlLive system. + +For this you need to add \tt{$(QMLLIVEPROJECT)/src/src.pri} to your project folder and use the \bold{LiveNodeEngine} class to be able to receive workspace changes and active document updates. By default the IPC will listen on the port 10234. + +Here is a short example of a minimal custom runtime: + +\code{.cpp} +#include <QtGui> +#include <QtDeclarative> + +// use live node header +#include "livenodeengine.h" + +int main(int argc, char** argv) +{ + QApplication app(argc, argv); + QDeclarativeView view; + + LiveNodeEngine node; + // let qml live instrument your view + node.setView(&view); + // where file updates should be stored relative to + node.setWorkspace("."); + // for local usage use the LocalPublisher + RemoteReceiver receiver; + receiver.registerNode(node); + // listen to ipc call from remote + receiver.listen(10234); + + view.setResizeMode(QDeclarativeView::SizeViewToRootObject); + view.show(); + return app.exec(); +} +\endcode + +*/ diff --git a/src/watcher.cpp b/src/watcher.cpp new file mode 100644 index 0000000..7b827d3 --- /dev/null +++ b/src/watcher.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "watcher.h" + + +/*! + \class Watcher + \internal + \brief A class which watches Directories and notifies you about changes + + A class which watches Directories and notifies you about every change in this Directory or in it's SubDirectories + */ + +/*! + Default Constructor using parent as parent + */ +Watcher::Watcher(QObject *parent) + : QObject(parent) + , m_watcher(new QFileSystemWatcher(this)) + , m_waitTimer(new QTimer(this)) +{ + connect(m_watcher, SIGNAL(directoryChanged(QString)), this, SLOT(recordChange(QString))); + connect(m_waitTimer, SIGNAL(timeout()), this, SLOT(notifyChanges())); + m_waitTimer->setInterval(100); + m_waitTimer->setSingleShot(true); +} + +/*! + Set the watching Directory to path. + + Every change within this Directory and it's sub Directories will be reported by + the directoriesChanged() signal + */ +void Watcher::setDirectory(const QString &path) +{ + m_rootDir = QDir(path); + if (!m_watcher->directories().isEmpty()) { + m_watcher->removePaths(m_watcher->directories()); + } + if (!m_watcher->files().isEmpty()) { + m_watcher->removePaths(m_watcher->files()); + } + addDirectoriesRecursively(m_rootDir.absolutePath()); +} + +/*! + Returns the Directory watched for changes + */ +QString Watcher::directory() const +{ + return m_rootDir.absolutePath(); +} + +/*! + Add path and all it's SubDirectory to the internal used QFileSystemWatcher + */ +void Watcher::addDirectoriesRecursively(const QString &path) +{ +// qDebug() << "scan: " << path; + if (!m_watcher->directories().contains(path)) { + m_watcher->addPath(path); + } + QDirIterator iter(path, QDir::Dirs|QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + while (iter.hasNext()) { + QDir entry(iter.next()); + if (!m_watcher->directories().contains(entry.absolutePath())) { + m_watcher->addPath(entry.absolutePath()); + + //If we couldn't add it we reached the filesystem limit + if (!m_watcher->directories().contains(entry.absolutePath())) { + qWarning() << "Watcher limit reached. Please reduce the number of files you are watching !!!"; + return; + } + } + } + +} + +/*! + Returns the given path relative to the watcher's Directory + /sa setDirectory, directory() + */ +QString Watcher::relativeFilePath(const QString &path) +{ + return m_rootDir.relativeFilePath(path); +} + +void Watcher::recordChange(const QString &path) +{ +// qDebug() << "Watcher::recordChange: " << path; + m_changes.append(path); + m_waitTimer->start(); +} + +/*! + Filters all the Directory changes. + + It tries to minimize the List of changes to the minimal common path. + Example: + + Changes: + + /home/qmllive/test/images + /home/qmllive/test + /home/user + + Will be filtered to: + + /home/qmllive/test + /home/user + + */ +void Watcher::notifyChanges() +{ +// qDebug() << "changes" << m_changes; + // sort to be able to avoid re-scan of recorded sub-folders + QStringList final; + QString top; + // sort changes so top-most dirs stay first + + //TODO: wrong assumption, since "aaa<a-umlaut>/" > "aaa/very/deep/hierarchy" + // we need to sort according to the number of sections when split by QDir::Separator + + m_changes.sort(); + foreach (const QString& entry, m_changes) { + if (!QDir(entry).exists()) { + // dir was removed + if (m_watcher->directories().contains(entry)) { + m_watcher->removePath(entry); + } + } else { + if (top.isNull() || !entry.startsWith(top)) { + top = entry; + final.append(entry); + } + } + } + m_changes.clear(); + // need to rescan these top-most dirs + foreach (const QString& entry, final) { + addDirectoriesRecursively(entry); + } + emit directoriesChanged(final); +// qDebug() << "watcher directories: " << m_watcher->directories(); +} + diff --git a/src/watcher.h b/src/watcher.h new file mode 100644 index 0000000..ad83a6d --- /dev/null +++ b/src/watcher.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> + +class Watcher : public QObject +{ + Q_OBJECT +public: + explicit Watcher(QObject *parent = 0); + void setDirectory(const QString& path); + QString directory() const; + QString relativeFilePath(const QString& path); +private Q_SLOTS: + void recordChange(const QString &path); + void notifyChanges(); +Q_SIGNALS: + void directoriesChanged(const QStringList& changes); + +private: + void addDirectoriesRecursively(const QString& path); + QFileSystemWatcher *m_watcher; + QDir m_rootDir; + QTimer *m_waitTimer; + QStringList m_changes; +}; + diff --git a/src/widgets/filesystemmodel.cpp b/src/widgets/filesystemmodel.cpp new file mode 100644 index 0000000..4eec2c7 --- /dev/null +++ b/src/widgets/filesystemmodel.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "filesystemmodel.h" + +FileSystemModel::FileSystemModel(QObject *parent) : + QFileSystemModel(parent) , + m_dirSelectable(true) +{ +} + +void FileSystemModel::setAllowedTypesFilter(QStringList allowed) +{ + m_allowedTypes = allowed; +} + +QStringList FileSystemModel::allowedTypesFilter() const +{ + return m_allowedTypes; +} + +void FileSystemModel::setDirectoriesSelectable(bool enabled) +{ + m_dirSelectable = enabled; +} + +bool FileSystemModel::directoriesSelectable() const +{ + return m_dirSelectable; +} + +Qt::ItemFlags FileSystemModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags f = QFileSystemModel::flags(index); + + if (isDir(index)) { + if (m_dirSelectable) + return f; + else + return f & ~Qt::ItemIsSelectable; + } + + QString path = filePath(index); + + foreach (QString type, m_allowedTypes) { + if (path.contains(QRegExp(type, Qt::CaseInsensitive, QRegExp::Wildcard))) + return f; + } + + return f & ~Qt::ItemIsSelectable; +} + + diff --git a/src/widgets/filesystemmodel.h b/src/widgets/filesystemmodel.h new file mode 100644 index 0000000..8ff17e9 --- /dev/null +++ b/src/widgets/filesystemmodel.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QFileSystemModel> + +class FileSystemModel : public QFileSystemModel +{ + Q_OBJECT +public: + explicit FileSystemModel(QObject *parent = 0); + + void setAllowedTypesFilter(QStringList allowed); + QStringList allowedTypesFilter() const; + + void setDirectoriesSelectable(bool enabled); + bool directoriesSelectable() const; + + Qt::ItemFlags flags(const QModelIndex &index) const; + +private: + QStringList m_allowedTypes; + bool m_dirSelectable; +}; + diff --git a/src/widgets/logview.cpp b/src/widgets/logview.cpp new file mode 100644 index 0000000..3ad4630 --- /dev/null +++ b/src/widgets/logview.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "logview.h" + +LogView::LogView(bool createLogger, QWidget *parent) + : QWidget(parent) + , m_log(new QPlainTextEdit(this)) + , m_logger(0) +{ + m_log->setReadOnly(true); + m_log->setMaximumBlockCount(1000); + m_log->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->addWidget(m_log); + setLayout(layout); + + if (createLogger) { + m_logger = new Logger(this); + connect(m_logger, SIGNAL(message(int,QString)), this, SLOT(appendToLog(int,QString))); + } +} + +void LogView::setIgnoreMessages(bool ignoreMessages) +{ + if (m_logger) + m_logger->setIgnoreMessages(ignoreMessages); +} + +void LogView::appendToLog(int type, const QString &msg, const QUrl &url, int line, int column) +{ + QMutexLocker l(&m_mutex); + + qreal baseValue = m_log->palette().color(QPalette::Base).valueF(); + QColor color = m_log->palette().color(QPalette::Text); + + switch (type) { + case QtWarningMsg: // yellow + color = baseValue < 0.5f ? QColor(255, 255, 128) : QColor(140, 140, 0); + break; + case QtCriticalMsg: // red + color = baseValue < 0.5f ? QColor(255, 64, 64) : QColor(165, 0, 0); + break; + case QtFatalMsg: // red + color = baseValue < 0.5f ? QColor(255, 64, 64) : QColor(165, 0, 0); + break; + case InternalInfo: // green + color = baseValue < 0.5f ? QColor(96, 255, 96) : QColor(128, 0, 0); + break; + case InternalError: // purple + color = baseValue < 0.5f ? QColor(196, 128, 196) : QColor(96, 0, 96); + break; + default: + break; + } + + QString s; + if (url.isValid()) { + s.append(url.isLocalFile() ? url.toLocalFile() : url.toString()); + s.append(QLatin1Char(':')); + } + if (line > 0) { + s.append(QString::number(line)); + s.append(QLatin1Char(':')); + } + Q_UNUSED(column); + if (!s.isEmpty()) + s.append(QLatin1Char(' ')); + + s.append(QString::fromLatin1("<b><font color=\"%2\">%1</font></b>") + .arg(msg) + .arg(color.name())); + + m_log->appendHtml(s); +} + +void LogView::appendToLog(const QList<QQmlError> &errors) +{ + foreach (const QQmlError &err, errors) { + if (!err.isValid()) + continue; + + QtMsgType type = QtDebugMsg; + + if (err.description().contains(QString::fromLatin1("error"), Qt::CaseInsensitive) || + err.description().contains(QString::fromLatin1("is not installed"), Qt::CaseInsensitive) || + err.description().contains(QString::fromLatin1("is not a type"), Qt::CaseInsensitive)) + type = QtCriticalMsg; + else if (err.description().contains(QString::fromLatin1("warning"), Qt::CaseInsensitive)) + type = QtWarningMsg; + + appendToLog(type, err.description(), err.url(), err.line(), err.column()); + } +} + +void LogView::clear() +{ + QMutexLocker l(&m_mutex); + m_log->clear(); +} + diff --git a/src/widgets/logview.h b/src/widgets/logview.h new file mode 100644 index 0000000..a5e1d49 --- /dev/null +++ b/src/widgets/logview.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtCore> +#include <QtGui> +#include <QtQuick> +#include <QtWidgets> + +#include "logger.h" + + +class LogView : public QWidget +{ + Q_OBJECT +public: + enum { + InternalInfo = QtDebugMsg - 1, + InternalError = QtDebugMsg - 2 + }; + + explicit LogView(bool createLogger = true, QWidget *parent = 0); +public slots: + void setIgnoreMessages(bool ignoreMessages); + void clear(); + void appendToLog(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1); + void appendToLog(const QList<QQmlError> &errors); + +private: + QPlainTextEdit *m_log; + + QMutex m_mutex; + Logger* m_logger; +}; diff --git a/src/widgets/widgets.pri b/src/widgets/widgets.pri new file mode 100644 index 0000000..2089397 --- /dev/null +++ b/src/widgets/widgets.pri @@ -0,0 +1,15 @@ +QT += network + +SOURCES += \ + $$PWD/logview.cpp \ + $$PWD/workspaceview.cpp \ + $$PWD/filesystemmodel.cpp \ + $$PWD/workspacedelegate.cpp \ + $$PWD/windowwidget.cpp + +HEADERS += \ + $$PWD/logview.h \ + $$PWD/workspaceview.h \ + $$PWD/filesystemmodel.h \ + $$PWD/workspacedelegate.h \ + $$PWD/windowwidget.h diff --git a/src/widgets/windowwidget.cpp b/src/widgets/windowwidget.cpp new file mode 100644 index 0000000..76bbedc --- /dev/null +++ b/src/widgets/windowwidget.cpp @@ -0,0 +1,279 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "windowwidget.h" +#include <QQuickView> +#include <QQuickItem> +#include <QGuiApplication> +#include <QDebug> +#include <QScrollBar> +#include <QResizeEvent> + +WindowWidget::WindowWidget(QWidget *parent) : + QAbstractScrollArea(parent), m_hostedWindow(0), m_resizing(false), m_centering(false) +{ + setFrameShape(QFrame::NoFrame); +} + +void WindowWidget::setHostedWindow(QQuickView *hostedWindow) +{ + QQuickView* oldView = 0; + if (m_hostedWindow) { + m_hostedWindow->removeEventFilter(this); + oldView = m_hostedWindow; + } + + m_hostedWindow = hostedWindow; + if (m_hostedWindow) { + m_hostedWindow->installEventFilter(this); + + // force creation of the TL window in order to get its handle + if (!testAttribute(Qt::WA_WState_Created)) + create(0, true, true); + + if (!windowHandle()) + qWarning("Could not get a valid windowhandle for our widget based window"); + + m_hostedWindow->setFlags(Qt::Tool | Qt::FramelessWindowHint); + m_hostedWindow->setParent(windowHandle()); + m_hostedWindow->setVisible(isVisible()); + + // this needs to be done in order to prevent showing uninitialized frames + m_hostedWindow->setGeometry(QRect(viewport()->mapToGlobal(QPoint()), viewport()->size())); + + viewport()->setBackgroundRole(backgroundRole()); + viewport()->setPalette(palette()); + viewport()->setBackgroundRole(QPalette::Background); + setFocusPolicy(Qt::StrongFocus); + m_hostedWindow->show(); + } + + if (oldView) { + oldView->hide(); + oldView->setParent(0); + } +} + +QQuickView *WindowWidget::hostedWindow() const +{ + return m_hostedWindow; +} + +void WindowWidget::setVisible(bool visible) +{ + QAbstractScrollArea::setVisible(visible); + if (m_hostedWindow) + m_hostedWindow->setVisible(visible); +} + +void WindowWidget::setCenteringEnabled(bool enabled) +{ + m_centering = enabled; + updateScrollBars(); +} + +QSize WindowWidget::sizeHint() const +{ + QSize s = qmlSize(); + + return s + QSize(frameWidth() * 2, frameWidth() * 2); +} + +void WindowWidget::forceInitialResize() +{ + if (m_hostedWindow && m_hostedWindow->resizeMode() == QQuickView::SizeRootObjectToView) { + m_hostedWindow->resize(size()); + } + updateGeometry(); + updateScrollBars(); + emit widthChanged(width()); + emit heightChanged(height()); + +} + +bool WindowWidget::event(QEvent *e) +{ + bool handled = false; + + if (m_hostedWindow) { + switch (e->type()) { + case QEvent::Wheel: { + QWheelEvent *oe = static_cast<QWheelEvent *>(e); + if (!viewport()->geometry().contains(oe->pos())) + break; + + QWheelEvent ne(m_hostedWindow->mapFromGlobal(oe->globalPos()), + oe->globalPos(), + oe->pixelDelta(), + oe->angleDelta(), + oe->delta(), + oe->orientation(), + oe->buttons(), + oe->modifiers()); + + qGuiApp->sendEvent(m_hostedWindow, &ne); + handled = true; + break; + } + case QEvent::KeyPress: + case QEvent::KeyRelease: { + qGuiApp->sendEvent(m_hostedWindow, e); + handled = true; + break; + } + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: { + QMouseEvent *oe = static_cast<QMouseEvent *>(e); + + if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick) { + if (!viewport()->geometry().contains(oe->pos())) + break; + } + + QMouseEvent ne(oe->type(), + m_hostedWindow->mapFromGlobal(oe->globalPos()), + m_hostedWindow->mapFromGlobal(oe->globalPos()), + oe->globalPos(), + oe->button(), + oe->buttons(), + oe->modifiers()); + + qGuiApp->sendEvent(m_hostedWindow, &ne); + handled = true; + break; + } + case QEvent::Resize: { + QResizeEvent* re = static_cast<QResizeEvent*>(e); + if (m_hostedWindow && m_hostedWindow->resizeMode() == QQuickView::SizeRootObjectToView) { + m_hostedWindow->resize(re->size()); + } + updateGeometry(); + updateScrollBars(); + if (re->oldSize().width() != re->size().width()) + emit widthChanged(re->size().width()); + if (re->oldSize().height() != re->size().height()) + emit heightChanged(re->size().height()); + break; + } + case QEvent::Hide: + m_hostedWindow->close(); + break; + default: + break; + } + } + return handled ? true : QAbstractScrollArea::event(e); +} + +bool WindowWidget::eventFilter(QObject *o, QEvent *e) +{ + if (o && o == m_hostedWindow) { + switch (e->type()) { + case QEvent::Resize: + updateScrollBars(); + break; + default: + break; + } + } + return QAbstractScrollArea::eventFilter(o, e); +} + +void WindowWidget::scrollContentsBy(int dx, int dy) +{ + Q_UNUSED(dx) + Q_UNUSED(dy) + + updateWindowPosition(); +} + +#include <QStyle> + +void WindowWidget::updateScrollBars() +{ + if (!m_hostedWindow) + return; + + if (window() && !m_resizing) { + m_resizing = true; + + QSize vpSize = viewport()->size(); + QSize vpMaxSize = maximumViewportSize(); + QSize wSize = qmlSize(); + + // does the window fit without scrollbars? + if (vpMaxSize.expandedTo(wSize) == vpMaxSize) + vpSize = vpMaxSize; + + // fix scrollbars + horizontalScrollBar()->setRange(0, (wSize - vpSize).width()); + horizontalScrollBar()->setPageStep(vpSize.width()); + verticalScrollBar()->setRange(0, (wSize - vpSize).height()); + verticalScrollBar()->setPageStep(vpSize.height()); + + //qWarning() << "wSize:" << wSize << "vpSize:" << vpSize << "vpRect" << viewport()->rect(); + //qWarning() << "Hrange:" << (wSize - vpSize).width() << "Hstep:" << vpSize.width(); + + updateWindowPosition(); + m_resizing = false; + } +} +void WindowWidget::updateWindowPosition() +{ + if (m_hostedWindow && m_hostedWindow->rootObject()) { + QSize wSize = qmlSize(); + Qt::LayoutDirection dir = layoutDirection(); + QRect scrolled = QStyle::visualRect(dir, viewport()->rect(), QRect(QPoint(-horizontalScrollBar()->value(), -verticalScrollBar()->value()), wSize)); + QRect aligned = QStyle::alignedRect(dir, m_centering ? Qt::AlignCenter : Qt::AlignTop | Qt::AlignLeft, wSize, viewport()->rect()); + + //qWarning() << "xAlign:" << aligned.x() << "xScrolled:" << scrolled.x(); + m_hostedWindow->setPosition(wSize.width() < viewport()->width() ? aligned.x() : scrolled.x(), + wSize.height() < viewport()->height() ? aligned.y() : scrolled.y()); + } +} + +QSize WindowWidget::qmlSize() const +{ + QSize s; + if (m_hostedWindow && m_hostedWindow->rootObject()) { + s = QSize(m_hostedWindow->rootObject()->width(), + m_hostedWindow->rootObject()->height()); + } + + if (s.width() <= 20) + s.setWidth(800); + if (s.height() <= 20) + s.setHeight(600); + + return s; +} + diff --git a/src/widgets/windowwidget.h b/src/widgets/windowwidget.h new file mode 100644 index 0000000..23d7900 --- /dev/null +++ b/src/widgets/windowwidget.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QAbstractScrollArea> +#include <QPointer> + +class QQuickView; + +class WindowWidget : public QAbstractScrollArea +{ + Q_OBJECT +public: + explicit WindowWidget(QWidget *parent = 0); + + QQuickView *hostedWindow() const; + void setHostedWindow(QQuickView *hostedWindow); + void setVisible(bool visible); + void setCenteringEnabled(bool enabled); + QSize sizeHint() const; + void forceInitialResize(); + +Q_SIGNALS: + void widthChanged(int w); + void heightChanged(int w); + +protected: + bool event(QEvent *e); + bool eventFilter(QObject *o, QEvent *e); + void scrollContentsBy(int dx, int dy); + +private: + void updateScrollBars(); + void updateWindowPosition(); + QSize qmlSize() const; + + QPointer<QQuickView> m_hostedWindow; + bool m_resizing; + bool m_centering; +}; + diff --git a/src/widgets/workspacedelegate.cpp b/src/widgets/workspacedelegate.cpp new file mode 100644 index 0000000..4e05227 --- /dev/null +++ b/src/widgets/workspacedelegate.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "workspacedelegate.h" + +WorkspaceDelegate::WorkspaceDelegate(FileSystemModel* model, QObject *parent) : + QStyledItemDelegate(parent), + m_model(model) +{ +} + +void WorkspaceDelegate::initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const +{ + QStyledItemDelegate::initStyleOption(option, index); + + if (option) { + if (m_model->isDir(index)) + return; + + QString path = m_model->filePath(index); + foreach (QString type, m_model->allowedTypesFilter()) + { + if (path.contains(QRegExp(type, Qt::CaseInsensitive, QRegExp::Wildcard))) + return; + } + + option->state &= ~QStyle::State_Enabled; + + QColor disabled = option->palette.color(QPalette::Disabled, QPalette::Text); + QColor enabled = option->palette.color(QPalette::Normal, QPalette::Text); + + if (disabled == enabled) { + QColor t = option->palette.color(QPalette::Disabled, QPalette::Text); + QColor b = option->palette.color(QPalette::Disabled, QPalette::Background); + + QColor selection = QColor::fromRgb((t.red() + b.red()) / 2, (t.green() + b.green()) / 2, (t.blue() + b.blue()) / 2); + + option->palette.setColor(QPalette::Disabled, QPalette::Text, selection); + } + } +} diff --git a/src/widgets/workspacedelegate.h b/src/widgets/workspacedelegate.h new file mode 100644 index 0000000..4ccb157 --- /dev/null +++ b/src/widgets/workspacedelegate.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QStyledItemDelegate> +#include "filesystemmodel.h" + +class WorkspaceDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + explicit WorkspaceDelegate(FileSystemModel* model, QObject *parent = 0); + + virtual void initStyleOption(QStyleOptionViewItem * option, const QModelIndex & index )const; + +private: + + FileSystemModel* m_model; +}; + diff --git a/src/widgets/workspaceview.cpp b/src/widgets/workspaceview.cpp new file mode 100644 index 0000000..ae06ca2 --- /dev/null +++ b/src/widgets/workspaceview.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#include "workspaceview.h" +#include "filesystemmodel.h" +#include "workspacedelegate.h" + +/*! + \class WorkspaceView + \internal + \brief A TreeView showing the Local Filesystem. + + The activateDocument() signal can be used to connect to a LiveHubEngine. + */ + + +/*! + Standard constructor using \a parent as parent + */ +WorkspaceView::WorkspaceView(QWidget *parent) + : QWidget(parent) + , m_view(new QTreeView(this)) + , m_model(new FileSystemModel(this)) +{ + // setup view +// m_view->setFocusPolicy(Qt::NoFocus); + m_view->setModel(m_model); + m_view->hideColumn(1); // size + m_view->hideColumn(2); // type + m_view->hideColumn(3); // modified time + + m_view->setItemDelegate(new WorkspaceDelegate(m_model, this)); + connect(m_view, SIGNAL(activated(QModelIndex)), this, SLOT(indexActivated(QModelIndex))); + + m_model->setAllowedTypesFilter(QStringList() << "*.qml" << "*.png" << "*.otf" << "*.ttf"); + + // setup layout + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(m_view); + layout->setMargin(1); + setLayout(layout); + + + m_view->setDragEnabled(true); + m_view->setDragDropMode(QAbstractItemView::DragOnly); +} + +/*! + * Sets the root workspace path to be displayed in the view to \a dirPath + */ +void WorkspaceView::setRootPath(const QString &dirPath) +{ + m_rootIndex = m_model->setRootPath(dirPath); + m_view->setRootIndex(m_model->index(dirPath)); +} + +/*! + * Activates the document by the given \a path + */ +void WorkspaceView::activateDocument(const QString &path) +{ + //qDebug() << "WorkspaceView::activateDocument" << path; + QModelIndex index = m_model->index(path); + selectIndex(index); +} + +void WorkspaceView::activateRootPath() +{ + selectIndex(m_rootIndex); + emit pathActivated(m_model->rootPath()); +} + +void WorkspaceView::goUp() +{ + QModelIndex index = m_view->currentIndex().parent(); + if (!index.isValid() || index == m_rootIndex) + return; + + selectIndex(index); +} + +/*! + * Returns the active, selected document. + */ +QString WorkspaceView::activeDocument() const +{ + return m_currentDocument; +} + +QString WorkspaceView::rootPath() const +{ + return m_model->rootPath(); +} + +void WorkspaceView::setDirectoriesSelectable(bool enabled) +{ + m_model->setDirectoriesSelectable(enabled); +} + +bool WorkspaceView::directoriesSelectable() const +{ + return m_model->directoriesSelectable(); +} + +/*! + * Emits a document activated signal based on a given \a index + */ +void WorkspaceView::indexActivated(const QModelIndex &index) +{ + if (!(m_model->flags(index) & Qt::ItemIsSelectable)) + return; + + QString path = m_model->filePath(index); + + m_currentDocument = path; + emit pathActivated(path); +} + +void WorkspaceView::selectIndex(const QModelIndex &index) +{ + QModelIndex parentIndex = index.parent(); + while (parentIndex.isValid()) { + m_view->expand(parentIndex); + parentIndex = parentIndex.parent(); + } + m_view->setCurrentIndex(index); + indexActivated(index); + //m_view->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); +} diff --git a/src/widgets/workspaceview.h b/src/widgets/workspaceview.h new file mode 100644 index 0000000..53b7b3b --- /dev/null +++ b/src/widgets/workspaceview.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +#pragma once + +#include <QtGui> +#include <QtWidgets> + +class FileSystemModel; + +class WorkspaceView : public QWidget +{ + Q_OBJECT +public: + explicit WorkspaceView(QWidget *parent = 0); + QString activeDocument() const; + QString rootPath() const; + void setDirectoriesSelectable(bool enabled); + bool directoriesSelectable() const; + +public Q_SLOTS: + void setRootPath(const QString& dirPath); + void activateDocument(const QString& path); + void activateRootPath(); + void goUp(); + +Q_SIGNALS: + void pathActivated(const QString& path); + +private Q_SLOTS: + void indexActivated(const QModelIndex& index); + +private: + void selectIndex(const QModelIndex& index); + QTreeView *m_view; + FileSystemModel *m_model; + QModelIndex m_rootIndex; + QString m_currentDocument; +}; diff --git a/testData/mixed/radio_0.png b/testData/mixed/radio_0.png Binary files differnew file mode 100644 index 0000000..fde357d --- /dev/null +++ b/testData/mixed/radio_0.png diff --git a/testData/mixed/radio_0_ro.png b/testData/mixed/radio_0_ro.png Binary files differnew file mode 100644 index 0000000..8b30856 --- /dev/null +++ b/testData/mixed/radio_0_ro.png diff --git a/testData/mixed/radio_1.png b/testData/mixed/radio_1.png Binary files differnew file mode 100644 index 0000000..c5d7d34 --- /dev/null +++ b/testData/mixed/radio_1.png diff --git a/testData/mixed/radio_2.png b/testData/mixed/radio_2.png Binary files differnew file mode 100644 index 0000000..f7bad20 --- /dev/null +++ b/testData/mixed/radio_2.png diff --git a/testData/mixed/radio_3.png b/testData/mixed/radio_3.png Binary files differnew file mode 100644 index 0000000..a27f2ca --- /dev/null +++ b/testData/mixed/radio_3.png diff --git a/testData/mixed/radio_disabled.png b/testData/mixed/radio_disabled.png Binary files differnew file mode 100644 index 0000000..5b30b10 --- /dev/null +++ b/testData/mixed/radio_disabled.png diff --git a/testData/mixed/radio_disabled_ro.png b/testData/mixed/radio_disabled_ro.png Binary files differnew file mode 100644 index 0000000..b4fb8ae --- /dev/null +++ b/testData/mixed/radio_disabled_ro.png diff --git a/testData/mixed/radio_nav_active.png b/testData/mixed/radio_nav_active.png Binary files differnew file mode 100644 index 0000000..17c7f4c --- /dev/null +++ b/testData/mixed/radio_nav_active.png diff --git a/testData/mixed/radio_nav_inactive.png b/testData/mixed/radio_nav_inactive.png Binary files differnew file mode 100644 index 0000000..9ca1bde --- /dev/null +++ b/testData/mixed/radio_nav_inactive.png diff --git a/testData/mixed/radio_selected.png b/testData/mixed/radio_selected.png Binary files differnew file mode 100644 index 0000000..629123d --- /dev/null +++ b/testData/mixed/radio_selected.png diff --git a/testData/qml/explicit-size.qml b/testData/qml/explicit-size.qml new file mode 100644 index 0000000..88ae8b5 --- /dev/null +++ b/testData/qml/explicit-size.qml @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +import QtQuick 2.0 + +Rectangle { + color: "#00ff00" + width: 100 + height: 400 +} diff --git a/testData/qml/no-explicit-size.qml b/testData/qml/no-explicit-size.qml new file mode 100644 index 0000000..e41462e --- /dev/null +++ b/testData/qml/no-explicit-size.qml @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +import QtQuick 2.0 + +Rectangle { + color: "#ffff00" +// width: 500 +// height: 300 +} diff --git a/testData/qml/two-windows.qml b/testData/qml/two-windows.qml new file mode 100644 index 0000000..3ffa5f0 --- /dev/null +++ b/testData/qml/two-windows.qml @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Window 2.1 + +Rectangle { + width: 400 + height: 400 + color: "red" + + Text { + anchors.centerIn: parent + text: "Window 1" + } + + Window { + width: 400 + height: 400 + visible: true + Rectangle { + anchors.fill: parent + color: "blue" + + Text { + anchors.centerIn: parent + text: "Window 2" + } + } + } +} diff --git a/tests/manual_tests/javascript/lib.js b/tests/manual_tests/javascript/lib.js new file mode 100644 index 0000000..413eb9b --- /dev/null +++ b/tests/manual_tests/javascript/lib.js @@ -0,0 +1 @@ +var counter = 0 diff --git a/tests/manual_tests/javascript/pragma_main.qml b/tests/manual_tests/javascript/pragma_main.qml new file mode 100644 index 0000000..353eff4 --- /dev/null +++ b/tests/manual_tests/javascript/pragma_main.qml @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +import QtQuick 2.0 +import "pragmalib.js" as PragmaLib +import "lib.js" as Lib + +Item { + + Component.onCompleted: { + for (var i= 0; i< 10; i++) { + print("Pragma Lib " + PragmaLib.counter++) + } + + for (var i= 0; i< 10; i++) { + print("Lib " + Lib.counter++) + } + } +} diff --git a/tests/manual_tests/javascript/pragmalib.js b/tests/manual_tests/javascript/pragmalib.js new file mode 100644 index 0000000..512cdf9 --- /dev/null +++ b/tests/manual_tests/javascript/pragmalib.js @@ -0,0 +1,3 @@ +.pragma library + +var counter = 0 diff --git a/tests/testipc/testipc.pro b/tests/testipc/testipc.pro new file mode 100644 index 0000000..6670176 --- /dev/null +++ b/tests/testipc/testipc.pro @@ -0,0 +1,19 @@ +QT += testlib + +QT -= gui +QT += network + +TARGET = tst_testipc +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +include(../../src/src.pri) + +SOURCES += tst_testipc.cpp + +DEFINES += SRCDIR=\\\"$$PWD/\\\" + +include(../../base.pri) + diff --git a/tests/testipc/tst_testipc.cpp b/tests/testipc/tst_testipc.cpp new file mode 100644 index 0000000..ca9f86c --- /dev/null +++ b/tests/testipc/tst_testipc.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +#include <QtCore> +#include <QtTest> +#include <QtNetwork> + +#include "ipc/ipcserver.h" +#include "ipc/ipcclient.h" + +class TestIpc : public QObject +{ + Q_OBJECT + +public: + TestIpc() {} +public slots: + void handleCall(QString method, QByteArray data) { + if (method == "echo(QString)") { + QDataStream stream(data); + QString message; + stream >> message; + qDebug() << method << ": " << message; + } + if (method == "sendFile(QString,QByteArray)") { + QDataStream stream(data); + QString path; + stream >> path; + QByteArray body; + stream >> body; + qDebug() << method << ": " << path; + } + } + +private Q_SLOTS: + void call() { + IpcServer peer1; + peer1.listen(10234); + connect(&peer1, SIGNAL(received(QString,QByteArray)), this, SLOT(handleCall(QString,QByteArray))); + IpcClient peer2; + peer2.setDestination("127.0.0.1", 10234); + QByteArray bytes; + QDataStream stream(&bytes, QIODevice::ReadWrite); + stream << QString("Hello IPC!"); + peer2.send("echo(QString)", bytes); + QSignalSpy received(&peer1, SIGNAL(received(QString,QByteArray))); + QTest::qWait(100); + QVERIFY(received.count() == 1); + } + + void sendFile() { + IpcServer peer1; + peer1.listen(10234); + connect(&peer1, SIGNAL(received(QString,QByteArray)), this, SLOT(handleCall(QString,QByteArray))); + IpcClient peer2; + peer2.setDestination("127.0.0.1", 10234); + QByteArray bytes; + QDataStream stream(&bytes, QIODevice::ReadWrite); + QString filePath("tst_testipc.cpp"); + stream << filePath; + stream << QString("hello").toLatin1(); + peer2.send("sendFile(QString,QByteArray)", bytes); + QSignalSpy received(&peer1, SIGNAL(received(QString,QByteArray))); + QTest::qWait(100); + QVERIFY(received.count() == 1); + } +}; + +QTEST_MAIN(TestIpc) + +#include "tst_testipc.moc" diff --git a/tests/tests.pro b/tests/tests.pro new file mode 100644 index 0000000..3179cdf --- /dev/null +++ b/tests/tests.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs + + +SUBDIRS += \ + testipc + #testsync \ + #http diff --git a/tests/testsync/testsync.pro b/tests/testsync/testsync.pro new file mode 100644 index 0000000..18aa2bb --- /dev/null +++ b/tests/testsync/testsync.pro @@ -0,0 +1,17 @@ +QT += testlib + +QT -= gui + +TARGET = tst_testsync +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +include(../../src/sync/sync.pri) + +SOURCES += tst_testsync.cpp + +DEFINES += SRCDIR=\\\"$$PWD/\\\" + +include(../../base.pri) diff --git a/tests/testsync/tst_testsync.cpp b/tests/testsync/tst_testsync.cpp new file mode 100644 index 0000000..135290a --- /dev/null +++ b/tests/testsync/tst_testsync.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Pelagicore AG +** Contact: http://www.qt.io/ or http://www.pelagicore.com/ +** +** This file is part of the QmlLive tool. +** +** $QT_BEGIN_LICENSE:GPL3-PELAGICORE$ +** Commercial License Usage +** Licensees holding valid commercial Pelagicore Application Manager +** 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, contact us at: +** http://www.pelagicore.com. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3 requirements will be +** met: http://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +** SPDX-License-Identifier: GPL-3.0 +** +****************************************************************************/ +#include <QtCore/QString> +#include <QtTest/QtTest> +#include "../../src/sync/syncengine.h" + +class TestSync : public QObject +{ + Q_OBJECT + +public: + TestSync() {} + +private Q_SLOTS: + void rsync() { + SyncEngine engine; + engine.setProgram("/usr/bin/rsync"); + engine.setLogin("jryannel"); + engine.setMachine("127.0.0.1"); + engine.setRemoteBasePath("/Users/jryannel/temp/temp1"); + engine.setLocalBasePath("/Users/jryannel/temp/temp2"); +// engine.setDryRun(true); + engine.start(); + engine.wait(); + } +}; + +QTEST_APPLESS_MAIN(TestSync) +#include "tst_testsync.moc" |